From 5ce975eed901763940abb0bcf8986c5186f8b704 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 27 Dec 2017 12:49:25 +0100 Subject: [PATCH] [dxbc] Fixed SV_VERTEXID and SV_INSTANCEID Apparently, these two system values ignore the base vertex and base instance from the draw call. This is not documented, but in line with what the AMD driver does on Windows. --- src/dxbc/dxbc_compiler.cpp | 44 ++++++--- src/dxbc/dxbc_compiler.h | 6 +- src/spirv/spirv_module.cpp | 30 ++++++ src/spirv/spirv_module.h | 10 ++ tests/d3d11/test_d3d11_triangle.cpp | 147 ++++++++++++++-------------- 5 files changed, 152 insertions(+), 85 deletions(-) diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index bc48a1a2..dbc15e47 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -2536,19 +2536,27 @@ namespace dxvk { DxbcRegMask mask) { switch (sv) { case DxbcSystemValue::VertexId: { - DxbcRegisterPointer ptrIn; - ptrIn.type.ctype = DxbcScalarType::Uint32; - ptrIn.type.ccount = 1; - ptrIn.id = m_vs.builtinVertexId; - return emitValueLoad(ptrIn); + const uint32_t typeId = getScalarTypeId(DxbcScalarType::Uint32); + + DxbcRegisterValue result; + result.type.ctype = DxbcScalarType::Uint32; + result.type.ccount = 1; + result.id = m_module.opISub(typeId, + m_module.opLoad(typeId, m_vs.builtinVertexId), + m_module.opLoad(typeId, m_vs.builtinBaseVertex)); + return result; } break; case DxbcSystemValue::InstanceId: { - DxbcRegisterPointer ptrIn; - ptrIn.type.ctype = DxbcScalarType::Uint32; - ptrIn.type.ccount = 1; - ptrIn.id = m_vs.builtinInstanceId; - return emitValueLoad(ptrIn); + const uint32_t typeId = getScalarTypeId(DxbcScalarType::Uint32); + + DxbcRegisterValue result; + result.type.ctype = DxbcScalarType::Uint32; + result.type.ccount = 1; + result.id = m_module.opISub(typeId, + m_module.opLoad(typeId, m_vs.builtinInstanceId), + m_module.opLoad(typeId, m_vs.builtinBaseInstance)); + return result; } break; default: @@ -2663,14 +2671,26 @@ namespace dxvk { m_vs.builtinVertexId = emitNewBuiltinVariable({ { DxbcScalarType::Uint32, 1, 0 }, spv::StorageClassInput }, - spv::BuiltInVertexId, // TODO test + spv::BuiltInVertexIndex, "vs_vertex_index"); m_vs.builtinInstanceId = emitNewBuiltinVariable({ { DxbcScalarType::Uint32, 1, 0 }, spv::StorageClassInput }, - spv::BuiltInInstanceId, // TODO test + spv::BuiltInInstanceIndex, // TODO test "vs_instance_index"); + + m_vs.builtinBaseVertex = emitNewBuiltinVariable({ + { DxbcScalarType::Uint32, 1, 0 }, + spv::StorageClassInput }, + spv::BuiltInBaseVertex, + "vs_base_vertex"); + + m_vs.builtinBaseInstance = emitNewBuiltinVariable({ + { DxbcScalarType::Uint32, 1, 0 }, + spv::StorageClassInput }, + spv::BuiltInBaseInstance, + "vs_base_instance"); } diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 9654ecbc..fc25eba8 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -92,8 +92,10 @@ namespace dxvk { struct DxbcCompilerVsPart { uint32_t functionId = 0; - uint32_t builtinVertexId = 0; - uint32_t builtinInstanceId = 0; + uint32_t builtinVertexId = 0; + uint32_t builtinInstanceId = 0; + uint32_t builtinBaseVertex = 0; + uint32_t builtinBaseInstance = 0; }; diff --git a/src/spirv/spirv_module.cpp b/src/spirv/spirv_module.cpp index b215a8e7..49fc0a0a 100644 --- a/src/spirv/spirv_module.cpp +++ b/src/spirv/spirv_module.cpp @@ -974,6 +974,21 @@ namespace dxvk { } + uint32_t SpirvModule::opISub( + uint32_t resultType, + uint32_t a, + uint32_t b) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpISub, 5); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(a); + m_code.putWord(b); + return resultId; + } + + uint32_t SpirvModule::opFAdd( uint32_t resultType, uint32_t a, @@ -989,6 +1004,21 @@ namespace dxvk { } + uint32_t SpirvModule::opFSub( + uint32_t resultType, + uint32_t a, + uint32_t b) { + uint32_t resultId = this->allocateId(); + + m_code.putIns (spv::OpFSub, 5); + m_code.putWord(resultType); + m_code.putWord(resultId); + m_code.putWord(a); + m_code.putWord(b); + return resultId; + } + + uint32_t SpirvModule::opSDiv( uint32_t resultType, uint32_t a, diff --git a/src/spirv/spirv_module.h b/src/spirv/spirv_module.h index 2d7d67af..f4a15fb1 100644 --- a/src/spirv/spirv_module.h +++ b/src/spirv/spirv_module.h @@ -354,11 +354,21 @@ namespace dxvk { uint32_t a, uint32_t b); + uint32_t opISub( + uint32_t resultType, + uint32_t a, + uint32_t b); + uint32_t opFAdd( uint32_t resultType, uint32_t a, uint32_t b); + uint32_t opFSub( + uint32_t resultType, + uint32_t a, + uint32_t b); + uint32_t opSDiv( uint32_t resultType, uint32_t a, diff --git a/tests/d3d11/test_d3d11_triangle.cpp b/tests/d3d11/test_d3d11_triangle.cpp index 183d42e0..67c888a0 100644 --- a/tests/d3d11/test_d3d11_triangle.cpp +++ b/tests/d3d11/test_d3d11_triangle.cpp @@ -19,25 +19,28 @@ struct Vertex { const std::string g_vertexShaderCode = "struct vs_out {\n" " float4 pos : SV_POSITION;\n" - " float2 coord : COORD;\n" + " uint vid : VID;\n" + " uint iid : IID;\n" "};\n" - "vs_out main(float4 vsIn : IN_POSITION) {\n" + "vs_out main(float4 vsIn : IN_POSITION,\n" + " uint vid : SV_VERTEXID,\n" + " uint iid : SV_INSTANCEID) {\n" " vs_out result;\n" " result.pos = vsIn;\n" - " result.coord = result.pos.xy;\n" + " result.vid = vid;\n" + " result.iid = iid;\n" " return result;\n" "}\n"; const std::string g_pixelShaderCode = "struct vs_out {\n" " float4 pos : SV_POSITION;\n" - " float2 coord : COORD;\n" + " uint vid : VID;\n" + " uint iid : IID;\n" "};\n" - "Texture1D t : register(t0);\n" - "sampler s : register(s0);\n" "cbuffer c_buffer { float4 ccolor[2]; };\n" "float4 main(vs_out ps_in) : SV_TARGET {\n" - " return ccolor[0] * t.Sample(s, 0.5f + 0.5f * ps_in.coord.y);\n" + " return 0.5f * (ccolor[min(ps_in.vid, 1u)] + ccolor[min(ps_in.iid, 1u)]);\n" "}\n"; class TriangleApp { @@ -73,7 +76,7 @@ public: swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; swapDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; swapDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - swapDesc.SampleDesc.Count = 1; + swapDesc.SampleDesc.Count = 8; swapDesc.SampleDesc.Quality = 0; swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapDesc.BufferCount = 2; @@ -94,10 +97,28 @@ public: if (FAILED(m_swapChain->ResizeTarget(&swapDesc.BufferDesc))) throw DxvkError("Failed to resize window"); - std::array vertexData = {{ - { -0.5f, -0.5f, 0.0f, 1.0f }, - { 0.0f, 0.5f, 0.0f, 1.0f }, - { 0.5f, -0.5f, 0.0f, 1.0f }, + std::array vertexData = {{ + { -0.25f, -0.15f, 0.0f, 1.0f }, + { -0.50f, -0.65f, 0.0f, 1.0f }, + { -0.75f, -0.15f, 0.0f, 1.0f }, + { 0.75f, -0.15f, 0.0f, 1.0f }, + { 0.50f, -0.65f, 0.0f, 1.0f }, + { 0.25f, -0.15f, 0.0f, 1.0f }, + { -0.75f, 0.15f, 0.0f, 1.0f }, + { -0.50f, 0.65f, 0.0f, 1.0f }, + { -0.25f, 0.15f, 0.0f, 1.0f }, + { 0.25f, 0.15f, 0.0f, 1.0f }, + { 0.50f, 0.65f, 0.0f, 1.0f }, + { 0.75f, 0.15f, 0.0f, 1.0f }, + { 0.25f, 0.75f, 0.0f, 1.0f }, + { 0.00f, 0.25f, 0.0f, 1.0f }, + { -0.25f, 0.75f, 0.0f, 1.0f }, + { -0.25f, -0.75f, 0.0f, 1.0f }, + { 0.00f, -0.25f, 0.0f, 1.0f }, + { 0.25f, -0.75f, 0.0f, 1.0f }, + { -0.25f, -0.25f, 0.0f, 1.0f }, + { 0.00f, 0.25f, 0.0f, 1.0f }, + { 0.25f, -0.25f, 0.0f, 1.0f }, }}; D3D11_BUFFER_DESC vertexDesc; @@ -116,9 +137,29 @@ public: if (FAILED(m_device->CreateBuffer(&vertexDesc, &vertexDataInfo, &m_vertexBuffer))) throw DxvkError("Failed to create vertex buffer"); + std::array indexData = {{ + 0, 1, 2, 0, 1, 2, 2, 1, 0 + }}; + + D3D11_BUFFER_DESC indexDesc; + indexDesc.ByteWidth = sizeof(uint32_t) * indexData.size(); + indexDesc.Usage = D3D11_USAGE_IMMUTABLE; + indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + indexDesc.CPUAccessFlags = 0; + indexDesc.MiscFlags = 0; + indexDesc.StructureByteStride = 0; + + D3D11_SUBRESOURCE_DATA indexDataInfo; + indexDataInfo.pSysMem = indexData.data(); + indexDataInfo.SysMemPitch = 0; + indexDataInfo.SysMemSlicePitch = 0; + + if (FAILED(m_device->CreateBuffer(&indexDesc, &indexDataInfo, &m_indexBuffer))) + throw DxvkError("Failed to create index buffer"); + std::array constantData = {{ { 0.03f, 0.03f, 0.03f, 1.0f }, - { 1.00f, 1.00f, 1.00f, 1.0f }, + { 1.00f, 0.00f, 0.00f, 1.0f }, }}; D3D11_BUFFER_DESC constantDesc; @@ -184,58 +225,6 @@ public: &m_vertexFormat))) throw DxvkError("Failed to create input layout"); - D3D11_SAMPLER_DESC samplerDesc; - samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.MipLODBias = 0.0f; - samplerDesc.MaxAnisotropy = 1.0f; - samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; - samplerDesc.BorderColor[0] = 0.0f; - samplerDesc.BorderColor[1] = 0.0f; - samplerDesc.BorderColor[2] = 0.0f; - samplerDesc.BorderColor[3] = 0.0f; - samplerDesc.MinLOD = 0.0f; - samplerDesc.MaxLOD = 0.0f; - - if (FAILED(m_device->CreateSamplerState( - &samplerDesc, - &m_sampler))) - throw DxvkError("Failed to create sampler"); - - D3D11_TEXTURE1D_DESC colorBufferDesc; - colorBufferDesc.Width = 4; - colorBufferDesc.MipLevels = 1; - colorBufferDesc.ArraySize = 1; - colorBufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - colorBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; - colorBufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - colorBufferDesc.CPUAccessFlags = 0; - colorBufferDesc.MiscFlags = 0; - - const std::array colorBufferContents = { - 0x00, 0x00, 0x00, 0xFF, - 0x80, 0x00, 0x00, 0xFF, - 0x80, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - }; - - D3D11_SUBRESOURCE_DATA colorBufferData; - colorBufferData.pSysMem = colorBufferContents.data(); - colorBufferData.SysMemPitch = 0; - colorBufferData.SysMemSlicePitch = 0; - - if (FAILED(m_device->CreateTexture1D( - &colorBufferDesc, - &colorBufferData, - &m_colorBuffer))) - throw DxvkError("Failed to create 1D texture"); - - if (FAILED(m_device->CreateShaderResourceView( - m_colorBuffer.ptr(), nullptr, &m_colorBufferSrv))) - throw DxvkError("Failed to create 1D texture view"); - } @@ -263,16 +252,35 @@ public: m_context->VSSetShader(m_vertexShader.ptr(), nullptr, 0); m_context->PSSetShader(m_pixelShader.ptr(), nullptr, 0); m_context->PSSetConstantBuffers(0, 1, &m_constantBuffer); - m_context->PSSetShaderResources(0, 1, &m_colorBufferSrv); - m_context->PSSetSamplers(0, 1, &m_sampler); UINT vsStride = sizeof(Vertex); UINT vsOffset = 0; + // Test normal draws with base vertex m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetInputLayout(m_vertexFormat.ptr()); m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); m_context->Draw(3, 0); + m_context->Draw(3, 3); + + // Test instanced draws with base instance and base vertex + vsOffset = 6 * sizeof(Vertex); + m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); + m_context->DrawInstanced(3, 1, 0, 1); + m_context->DrawInstanced(3, 1, 3, 1); + + // Test indexed draws with base vertex and base index + vsOffset = 12 * sizeof(Vertex); + m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); + m_context->IASetIndexBuffer(m_indexBuffer.ptr(), DXGI_FORMAT_R32_UINT, 0); + m_context->DrawIndexed(3, 0, 0); + m_context->DrawIndexed(3, 3, 3); + + // Test default backface culling + vsOffset = 18 * sizeof(Vertex); + m_context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &vsStride, &vsOffset); + m_context->DrawIndexed(3, 6, 0); + m_context->OMSetRenderTargets(0, nullptr, nullptr); m_swapChain->Present(0, 0); @@ -320,13 +328,10 @@ private: Com m_buffer; Com m_bufferView; Com m_constantBuffer; + Com m_indexBuffer; Com m_vertexBuffer; Com m_vertexFormat; - Com m_sampler; - Com m_colorBuffer; - Com m_colorBufferSrv; - Com m_vertexShader; Com m_pixelShader;