[dxbc] Implemented proper resource slot mapping

This commit is contained in:
Philip Rebohle 2017-12-08 22:30:41 +01:00
parent feab720ddb
commit c90bc3e946
16 changed files with 158 additions and 43 deletions

View File

@ -3,6 +3,8 @@
#include "d3d11_context.h"
#include "d3d11_device.h"
#include "../dxbc/dxbc_util.h"
namespace dxvk {
D3D11DeviceContext::D3D11DeviceContext(
@ -638,6 +640,7 @@ namespace dxvk {
switch (binding.format) {
case DXGI_FORMAT_R16_UINT: indexType = VK_INDEX_TYPE_UINT16; break;
case DXGI_FORMAT_R32_UINT: indexType = VK_INDEX_TYPE_UINT32; break;
default: Logger::err(str::format("D3D11: Invalid index format: ", binding.format));
}
m_context->bindIndexBuffer(
@ -696,7 +699,7 @@ namespace dxvk {
UINT NumBuffers,
ID3D11Buffer* const* ppConstantBuffers) {
this->BindConstantBuffers(
D3D11ShaderStage::VertexShader,
DxbcProgramType::VertexShader,
&m_state.vs.constantBuffers,
StartSlot, NumBuffers,
ppConstantBuffers);
@ -966,7 +969,7 @@ namespace dxvk {
UINT NumBuffers,
ID3D11Buffer* const* ppConstantBuffers) {
this->BindConstantBuffers(
D3D11ShaderStage::PixelShader,
DxbcProgramType::PixelShader,
&m_state.vs.constantBuffers,
StartSlot, NumBuffers,
ppConstantBuffers);
@ -1329,7 +1332,7 @@ namespace dxvk {
void D3D11DeviceContext::BindConstantBuffers(
D3D11ShaderStage ShaderStage,
DxbcProgramType ShaderStage,
D3D11ConstantBufferBindings* pBindings,
UINT StartSlot,
UINT NumBuffers,
@ -1343,18 +1346,25 @@ namespace dxvk {
if (pBindings->at(StartSlot + i) != buffer) {
pBindings->at(StartSlot + i) = buffer;
DxvkBufferBinding dxvkBinding;
DxvkBufferBinding bindingInfo;
if (buffer != nullptr) {
dxvkBinding = DxvkBufferBinding(
bindingInfo = DxvkBufferBinding(
buffer->GetDXVKBuffer(),
0, VK_WHOLE_SIZE);
}
// TODO compute actual slot index
VkPipelineBindPoint bindPoint
= ShaderStage == DxbcProgramType::ComputeShader
? VK_PIPELINE_BIND_POINT_COMPUTE
: VK_PIPELINE_BIND_POINT_GRAPHICS;
uint32_t slotId = computeResourceSlotId(
ShaderStage, DxbcBindingType::ConstantBuffer,
StartSlot + i);
m_context->bindResourceBuffer(
VK_PIPELINE_BIND_POINT_GRAPHICS, 0,
dxvkBinding);
bindPoint, slotId, bindingInfo);
}
}
}
@ -1369,8 +1379,9 @@ namespace dxvk {
std::array<VkViewport, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> viewports;
std::array<VkRect2D, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE> scissors;
// FIXME compute proper viewport coordinates (vertical origin).
// D3D11's coordinate system has its origin in the bottom left.
// D3D11's coordinate system has its origin in the bottom left,
// but the viewport coordinates are aligned to the top-left
// corner so we can get away with flipping the viewport.
for (uint32_t i = 0; i < m_state.rs.numViewports; i++) {
const D3D11_VIEWPORT& vp = m_state.rs.viewports.at(i);
@ -1396,7 +1407,6 @@ namespace dxvk {
// TODO D3D11 docs aren't clear about what should happen
// when there are undefined scissor rects for a viewport.
// Figure out what it does on Windows.
// FIXME Compute correct vertical position
if (enableScissorTest && (i < m_state.rs.numScissors)) {
const D3D11_RECT& sr = m_state.rs.scissors.at(i);

View File

@ -555,7 +555,7 @@ namespace dxvk {
D3D11ContextState m_state;
void BindConstantBuffers(
D3D11ShaderStage ShaderStage,
DxbcProgramType ShaderStage,
D3D11ConstantBufferBindings* pBindings,
UINT StartSlot,
UINT NumBuffers,

View File

@ -10,15 +10,6 @@
namespace dxvk {
enum class D3D11ShaderStage {
VertexShader = 0,
HullShader = 1,
DomainShader = 2,
GeometryShader = 3,
PixelShader = 4,
ComputeShader = 5,
};
using D3D11ConstantBufferBindings = std::array<
Com<D3D11Buffer>, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT>;

44
src/dxbc/dxbc_util.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "dxbc_util.h"
namespace dxvk {
uint32_t computeResourceSlotId(
DxbcProgramType shaderStage,
DxbcBindingType bindingType,
uint32_t bindingIndex) {
if (shaderStage == DxbcProgramType::ComputeShader) {
// 0 - 13: Constant buffers
// 14 - 29: Samplers
// 30 - 157: Shader resources
// 158 - 221: Uniform access views
switch (bindingType) {
case DxbcBindingType::ConstantBuffer: return bindingIndex + 0;
case DxbcBindingType::ImageSampler: return bindingIndex + 14;
case DxbcBindingType::ShaderResource: return bindingIndex + 30;
case DxbcBindingType::UnorderedAccessView:return bindingIndex + 158;
default: Logger::err("computeResourceSlotId: Invalid resource type");
}
} else {
// Global resource slots
// 0 - 7: Uniform access views
// 8 - 11: Stream output buffers
// Per-stage resource slots:
// 0 - 13: Constant buffers
// 14 - 29: Samplers
// 30 - 157: Shader resources
const uint32_t stageOffset = 12 + 158 * static_cast<uint32_t>(shaderStage);
switch (bindingType) {
case DxbcBindingType::UnorderedAccessView:return bindingIndex + 0;
case DxbcBindingType::StreamOutputBuffer: return bindingIndex + 8;
case DxbcBindingType::ConstantBuffer: return bindingIndex + stageOffset + 0;
case DxbcBindingType::ImageSampler: return bindingIndex + stageOffset + 14;
case DxbcBindingType::ShaderResource: return bindingIndex + stageOffset + 30;
default: Logger::err("computeResourceSlotId: Invalid resource type");
}
}
return 0;
}
}

35
src/dxbc/dxbc_util.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include "dxbc_common.h"
namespace dxvk {
/**
* \brief Resource type
*
* The type of a shader resource. Used
* to determine the DXVK resource slot.
*/
enum DxbcBindingType : uint32_t {
ConstantBuffer = 0,
ShaderResource = 1,
ImageSampler = 2,
UnorderedAccessView = 3,
StreamOutputBuffer = 4,
};
/**
* \brief Computes the DXVK resource slot for a binding
*
* \param [in] shaderStage The target shader stage
* \param [in] bindingType Type of the resource
* \param [in] bindingIndex Resource binding index
* \returns DXVK resource slot index
*/
uint32_t computeResourceSlotId(
DxbcProgramType shaderStage,
DxbcBindingType bindingType,
uint32_t bindingIndex);
}

View File

@ -6,7 +6,8 @@
namespace dxvk {
DxbcCodeGen::DxbcCodeGen() {
DxbcCodeGen::DxbcCodeGen(DxbcProgramType shaderStage)
: m_shaderStage(shaderStage) {
m_module.setMemoryModel(
spv::AddressingModelLogical,
spv::MemoryModelGLSL450);
@ -52,14 +53,20 @@ namespace dxvk {
m_module.defPointerType(structType, spv::StorageClassUniform),
spv::StorageClassUniform);
uint32_t bindingId = computeResourceSlotId(m_shaderStage,
DxbcBindingType::ConstantBuffer, bufferId);
m_module.setDebugName(varIndex, str::format("cb", bufferId).c_str());
m_module.decorateDescriptorSet(varIndex, 0);
m_module.decorateBinding(varIndex, 0);
m_module.decorateBinding(varIndex, bindingId);
m_constantBuffers.at(bufferId).varId = varIndex;
m_constantBuffers.at(bufferId).size = elementCount;
// TODO compute resource slot index
m_resourceSlots.push_back({ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER });
DxvkResourceSlot resource;
resource.slot = bindingId;
resource.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
m_resourceSlots.push_back(resource);
}

View File

@ -4,6 +4,7 @@
#include "../dxbc_common.h"
#include "../dxbc_decoder.h"
#include "../dxbc_type.h"
#include "../dxbc_util.h"
#include "../../spirv/spirv_module.h"
@ -46,7 +47,7 @@ namespace dxvk {
public:
DxbcCodeGen();
DxbcCodeGen(DxbcProgramType shaderStage);
virtual ~DxbcCodeGen();
@ -149,6 +150,8 @@ namespace dxvk {
constexpr static uint32_t PerVertex_CullDist = 2;
constexpr static uint32_t PerVertex_ClipDist = 3;
const DxbcProgramType m_shaderStage;
SpirvModule m_module;
std::vector<uint32_t> m_entryPointInterfaces;

View File

@ -2,8 +2,8 @@
namespace dxvk {
DxbcPsCodeGen::DxbcPsCodeGen(
const Rc<DxbcIsgn>& osgn) {
DxbcPsCodeGen::DxbcPsCodeGen(const Rc<DxbcIsgn>& osgn)
: DxbcCodeGen(DxbcProgramType::PixelShader) {
m_module.enableCapability(spv::CapabilityShader);
m_module.enableCapability(spv::CapabilityCullDistance);
m_module.enableCapability(spv::CapabilityClipDistance);

View File

@ -2,7 +2,8 @@
namespace dxvk {
DxbcVsCodeGen::DxbcVsCodeGen(const Rc<DxbcIsgn>& isgn) {
DxbcVsCodeGen::DxbcVsCodeGen(const Rc<DxbcIsgn>& isgn)
: DxbcCodeGen(DxbcProgramType::VertexShader) {
m_module.enableCapability(spv::CapabilityShader);
m_module.enableCapability(spv::CapabilityCullDistance);
m_module.enableCapability(spv::CapabilityClipDistance);

View File

@ -9,6 +9,7 @@ dxbc_src = files([
'dxbc_names.cpp',
'dxbc_reader.cpp',
'dxbc_type.cpp',
'dxbc_util.cpp',
'gen/dxbc_gen_common.cpp',
'gen/dxbc_gen_pixel.cpp',

View File

@ -330,8 +330,8 @@ namespace dxvk {
DxvkContextState m_state;
DxvkBarrierSet m_barriers;
DxvkShaderResourceSlots m_cResources = { 1024 };
DxvkShaderResourceSlots m_gResources = { 4096 };
DxvkShaderResourceSlots m_cResources = { 256 };
DxvkShaderResourceSlots m_gResources = { 1024 };
void renderPassBegin();
void renderPassEnd();

View File

@ -26,7 +26,7 @@ namespace dxvk {
}
uint32_t DxvkDescriptorSlotMapping::getBindingId(uint32_t slot) {
uint32_t DxvkDescriptorSlotMapping::getBindingId(uint32_t slot) const {
// This won't win a performance competition, but the number
// of bindings used by a shader is usually much smaller than
// the number of resource slots available to the system.

View File

@ -74,7 +74,7 @@ namespace dxvk {
* \returns Binding index, or \c InvalidBinding
*/
uint32_t getBindingId(
uint32_t slot);
uint32_t slot) const;
private:

View File

@ -66,8 +66,21 @@ namespace dxvk {
Rc<DxvkShaderModule> DxvkShader::createShaderModule(
const Rc<vk::DeviceFn>& vkd,
const DxvkDescriptorSlotMapping& mapping) const {
// TODO apply mapping
return new DxvkShaderModule(vkd, m_stage, m_code);
// Iterate over the code and replace every resource slot
// index with the corresponding mapped binding index.
SpirvCodeBuffer spirvCode = m_code;
for (auto ins : spirvCode) {
if (ins.opCode() == spv::OpDecorate
&& ins.arg(2) == spv::DecorationBinding) {
const uint32_t oldBinding = ins.arg(3);
const uint32_t newBinding = mapping.getBindingId(oldBinding);
ins.setArg(3, newBinding);
}
}
return new DxvkShaderModule(vkd, m_stage, spirvCode);
}

View File

@ -48,7 +48,7 @@ namespace dxvk {
* block. The header, if any, will be skipped over.
* \returns Instruction iterator
*/
SpirvInstructionIterator begin() const {
SpirvInstructionIterator begin() {
return SpirvInstructionIterator(m_code.data(), m_code.size());
}
@ -58,7 +58,7 @@ namespace dxvk {
* Points to the end of the instruction block.
* \returns Instruction iterator
*/
SpirvInstructionIterator end() const {
SpirvInstructionIterator end() {
return SpirvInstructionIterator(nullptr, 0);
}

View File

@ -19,8 +19,7 @@ namespace dxvk {
public:
SpirvInstruction() { }
SpirvInstruction(
const uint32_t* code, uint32_t size)
SpirvInstruction(uint32_t* code, uint32_t size)
: m_code(code), m_size(size) { }
/**
@ -54,10 +53,21 @@ namespace dxvk {
return id < m_size ? m_code[id] : 0;
}
/**
* \brief Changes the value of an argument
*
* \param [in] id Argument index, starting at 1
* \param [in] word New argument word
*/
void setArg(uint32_t id, uint32_t word) const {
if (id < m_size)
m_code[id] = word;
}
private:
uint32_t const* m_code = nullptr;
uint32_t m_size = 0;
uint32_t* m_code = nullptr;
uint32_t m_size = 0;
};
@ -73,7 +83,7 @@ namespace dxvk {
public:
SpirvInstructionIterator() { }
SpirvInstructionIterator(const uint32_t* code, uint32_t size)
SpirvInstructionIterator(uint32_t* code, uint32_t size)
: m_code(size != 0 ? code : nullptr), m_size(size) {
if ((size >= 5) && (m_code[0] == spv::MagicNumber))
this->advance(5);
@ -100,8 +110,8 @@ namespace dxvk {
private:
uint32_t const* m_code = nullptr;
uint32_t m_size = 0;
uint32_t* m_code = nullptr;
uint32_t m_size = 0;
void advance(uint32_t n) {
if (n < m_size) {