diff -Nru dxvk-0.95+ds1/debian/changelog dxvk-0.96+ds1/debian/changelog --- dxvk-0.95+ds1/debian/changelog 2019-01-13 00:28:29.000000000 +0000 +++ dxvk-0.96+ds1/debian/changelog 2019-01-27 04:21:44.000000000 +0000 @@ -1,3 +1,9 @@ +dxvk (0.96+ds1-1) unstable; urgency=medium + + * New upstream version. + + -- Alexandre Viau Sat, 26 Jan 2019 23:21:44 -0500 + dxvk (0.95+ds1-1) unstable; urgency=medium * New upstream version. diff -Nru dxvk-0.95+ds1/LICENSE dxvk-0.96+ds1/LICENSE --- dxvk-0.95+ds1/LICENSE 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/LICENSE 2019-01-26 17:41:48.000000000 +0000 @@ -1,4 +1,4 @@ - Copyright (c) 2017 Philip Rebohle + Copyright (c) 2017-2019 Philip Rebohle zlib/libpng license diff -Nru dxvk-0.95+ds1/meson.build dxvk-0.96+ds1/meson.build --- dxvk-0.95+ds1/meson.build 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/meson.build 2019-01-26 17:41:48.000000000 +0000 @@ -1,4 +1,4 @@ -project('dxvk', ['c', 'cpp'], version : 'v0.95', meson_version : '>= 0.43') +project('dxvk', ['c', 'cpp'], version : 'v0.96', meson_version : '>= 0.43') cpu_family = target_machine.cpu_family() diff -Nru dxvk-0.95+ds1/RELEASE dxvk-0.96+ds1/RELEASE --- dxvk-0.95+ds1/RELEASE 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/RELEASE 2019-01-26 17:41:48.000000000 +0000 @@ -1 +1 @@ -0.95 +0.96 diff -Nru dxvk-0.95+ds1/src/d3d11/d3d11_context.cpp dxvk-0.96+ds1/src/d3d11/d3d11_context.cpp --- dxvk-0.95+ds1/src/d3d11/d3d11_context.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/d3d11/d3d11_context.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -1439,7 +1439,7 @@ constexpr VkDeviceSize stride = sizeof(VkDrawIndirectCommand); auto cmdData = static_cast(m_cmdData); - bool useMultiDraw = cmdData && cmdData->type == D3D11CmdType::DrawIndirectIndexed + bool useMultiDraw = cmdData && cmdData->type == D3D11CmdType::DrawIndirect && cmdData->offset + cmdData->count * stride == AlignedByteOffsetForArgs && m_device->features().core.features.multiDrawIndirect; @@ -2688,14 +2688,24 @@ auto rasterizerState = static_cast(pRasterizerState); + bool currScissorEnable = m_state.rs.state != nullptr + ? m_state.rs.state->Desc()->ScissorEnable + : false; + + bool nextScissorEnable = rasterizerState != nullptr + ? rasterizerState->Desc()->ScissorEnable + : false; + if (m_state.rs.state != rasterizerState) { m_state.rs.state = rasterizerState; - + // In D3D11, the rasterizer state defines whether the // scissor test is enabled, so we have to update the // scissor rectangles as well. ApplyRasterizerState(); - ApplyViewportState(); + + if (currScissorEnable != nextScissorEnable) + ApplyViewportState(); } } diff -Nru dxvk-0.95+ds1/src/d3d11/d3d11_device.cpp dxvk-0.96+ds1/src/d3d11/d3d11_device.cpp --- dxvk-0.95+ds1/src/d3d11/d3d11_device.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/d3d11/d3d11_device.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -613,8 +613,8 @@ if (!m_dxvkDevice->features().extTransformFeedback.transformFeedback) { Logger::err( "D3D11: CreateGeometryShaderWithStreamOutput:" - "\n Transform feedback not supoorted by device"); - return m_d3d11Options.fakeStreamOutSupport ? S_OK : E_NOTIMPL; + "\n Transform feedback not supported by device"); + return S_OK; } // Zero-init some counterss so that we can increment @@ -1736,7 +1736,8 @@ m_d3d11Device (this, FeatureLevel, FeatureFlags), m_d3d11Presenter(this, &m_d3d11Device), m_d3d11Interop (this, &m_d3d11Device), - m_wineFactory (&m_d3d11Presenter) { + m_wineFactory (&m_d3d11Presenter), + m_frameLatencyCap(m_d3d11Device.GetOptions()->maxFrameLatency) { for (uint32_t i = 0; i < m_frameEvents.size(); i++) m_frameEvents[i] = new DxvkEvent(); } diff -Nru dxvk-0.95+ds1/src/d3d11/d3d11_main.cpp dxvk-0.96+ds1/src/d3d11/d3d11_main.cpp --- dxvk-0.95+ds1/src/d3d11/d3d11_main.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/d3d11/d3d11_main.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -118,7 +118,7 @@ Logger::warn("D3D11CreateDevice: Unsupported driver type"); // We'll use the first adapter returned by a DXGI factory - if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast(&dxgiFactory)))) { + if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory), reinterpret_cast(&dxgiFactory)))) { Logger::err("D3D11CreateDevice: Failed to create a DXGI factory"); return E_FAIL; } diff -Nru dxvk-0.95+ds1/src/d3d11/d3d11_options.cpp dxvk-0.96+ds1/src/d3d11/d3d11_options.cpp --- dxvk-0.95+ds1/src/d3d11/d3d11_options.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/d3d11/d3d11_options.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -5,16 +5,15 @@ namespace dxvk { D3D11Options::D3D11Options(const Config& config) { - this->allowMapFlagNoWait = config.getOption("d3d11.allowMapFlagNoWait", false); - this->dcSingleUseMode = config.getOption("d3d11.dcSingleUseMode", true); - this->fakeStreamOutSupport = config.getOption("d3d11.fakeStreamOutSupport", false); + this->allowMapFlagNoWait = config.getOption("d3d11.allowMapFlagNoWait", false); + this->dcSingleUseMode = config.getOption("d3d11.dcSingleUseMode", true); this->zeroInitWorkgroupMemory = config.getOption("d3d11.zeroInitWorkgroupMemory", false); - this->maxTessFactor = config.getOption("d3d11.maxTessFactor", 0); - this->samplerAnisotropy = config.getOption("d3d11.samplerAnisotropy", -1); - this->deferSurfaceCreation = config.getOption("dxgi.deferSurfaceCreation", false); + this->maxTessFactor = config.getOption("d3d11.maxTessFactor", 0); + this->samplerAnisotropy = config.getOption("d3d11.samplerAnisotropy", -1); + this->deferSurfaceCreation = config.getOption("dxgi.deferSurfaceCreation", false); this->numBackBuffers = config.getOption("dxgi.numBackBuffers", 0); + this->maxFrameLatency = config.getOption("dxgi.maxFrameLatency", 0); this->syncInterval = config.getOption("dxgi.syncInterval", -1); - this->syncMode = D3D11SwapChainSyncMode(config.getOption("dxgi.syncMode", 0)); } } \ No newline at end of file diff -Nru dxvk-0.95+ds1/src/d3d11/d3d11_options.h dxvk-0.96+ds1/src/d3d11/d3d11_options.h --- dxvk-0.95+ds1/src/d3d11/d3d11_options.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/d3d11/d3d11_options.h 2019-01-26 17:41:48.000000000 +0000 @@ -8,14 +8,6 @@ namespace dxvk { - /** - * \brief Sync mode - */ - enum class D3D11SwapChainSyncMode : int32_t { - Default = 0, - Mailbox = 1, - }; - struct D3D11Options { D3D11Options(const Config& config); /// Handle D3D11_MAP_FLAG_DO_NOT_WAIT properly. @@ -33,14 +25,6 @@ /// than once. bool dcSingleUseMode; - /// Fakes stream output support. - /// - /// Temporary hack that fixes issues in some games - /// which technically need stream output but work - /// well enough without it. Will be removed once - /// Stream Output is properly supported in DXVK. - bool fakeStreamOutSupport; - /// Zero-initialize workgroup memory /// /// Workargound for games that don't initialize @@ -68,13 +52,14 @@ /// passed to IDXGISwapChain::Present. int32_t syncInterval; + /// Override maximum frame latency if the app specifies + /// a higher value. May help with frame timing issues. + int32_t maxFrameLatency; + /// Defer surface creation until first present call. This /// fixes issues with games that create multiple swap chains /// for a single window that may interfere with each other. bool deferSurfaceCreation; - - /// Vsync mode - D3D11SwapChainSyncMode syncMode; }; } \ No newline at end of file diff -Nru dxvk-0.95+ds1/src/d3d11/d3d11_rasterizer.cpp dxvk-0.96+ds1/src/d3d11/d3d11_rasterizer.cpp --- dxvk-0.95+ds1/src/d3d11/d3d11_rasterizer.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/d3d11/d3d11_rasterizer.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -41,13 +41,16 @@ ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE; - // Let's treat the depth bias as enabled by default - m_state.depthBiasEnable = VK_TRUE; - m_state.depthBiasConstant = static_cast(desc.DepthBias); - m_state.depthBiasClamp = desc.DepthBiasClamp; - m_state.depthBiasSlope = desc.SlopeScaledDepthBias; - m_state.depthClampEnable = desc.DepthClipEnable ? VK_FALSE : VK_TRUE; + // In the backend we treat depth bias as a dynamic state because + // some games like to put random/uninitialized numbers here, but + // we do not need to enable it in case the parameters are both 0. + m_state.depthBiasEnable = desc.DepthBias != 0 || desc.SlopeScaledDepthBias != 0.0f; + m_state.depthClipEnable = desc.DepthClipEnable; m_state.sampleCount = VkSampleCountFlags(desc.ForcedSampleCount); + + m_depthBias.depthBiasConstant = float(desc.DepthBias); + m_depthBias.depthBiasSlope = desc.SlopeScaledDepthBias; + m_depthBias.depthBiasClamp = desc.DepthBiasClamp; if (desc.AntialiasedLineEnable) Logger::err("D3D11RasterizerState: Antialiased lines not supported"); @@ -108,6 +111,9 @@ void D3D11RasterizerState::BindToContext(const Rc& ctx) { ctx->setRasterizerState(m_state); + + if (m_state.depthBiasEnable) + ctx->setDepthBias(m_depthBias); } diff -Nru dxvk-0.95+ds1/src/d3d11/d3d11_rasterizer.h dxvk-0.96+ds1/src/d3d11/d3d11_rasterizer.h --- dxvk-0.95+ds1/src/d3d11/d3d11_rasterizer.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/d3d11/d3d11_rasterizer.h 2019-01-26 17:41:48.000000000 +0000 @@ -34,6 +34,10 @@ void STDMETHODCALLTYPE GetDesc1( D3D11_RASTERIZER_DESC1* pDesc) final; + const D3D11_RASTERIZER_DESC1* Desc() const { + return &m_desc; + } + void BindToContext( const Rc& ctx); @@ -54,6 +58,7 @@ D3D11Device* const m_device; D3D11_RASTERIZER_DESC1 m_desc; DxvkRasterizerState m_state; + DxvkDepthBias m_depthBias; D3D10RasterizerState m_d3d10; }; diff -Nru dxvk-0.95+ds1/src/d3d11/d3d11_swapchain.cpp dxvk-0.96+ds1/src/d3d11/d3d11_swapchain.cpp --- dxvk-0.95+ds1/src/d3d11/d3d11_swapchain.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/d3d11/d3d11_swapchain.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -572,11 +572,9 @@ m_rsState.polygonMode = VK_POLYGON_MODE_FILL; m_rsState.cullMode = VK_CULL_MODE_BACK_BIT; m_rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - m_rsState.depthClampEnable = VK_FALSE; + m_rsState.depthClipEnable = VK_FALSE; m_rsState.depthBiasEnable = VK_FALSE; - m_rsState.depthBiasConstant = 0.0f; - m_rsState.depthBiasClamp = 0.0f; - m_rsState.depthBiasSlope = 0.0f; + m_rsState.sampleCount = VK_SAMPLE_COUNT_1_BIT; m_msState.sampleMask = 0xffffffff; m_msState.enableAlphaToCoverage = VK_FALSE; @@ -675,6 +673,9 @@ uint32_t n = 0; switch (Format) { + default: + Logger::warn(str::format("D3D11SwapChain: Unexpected format: ", m_desc.Format)); + case DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM: { pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; @@ -695,9 +696,6 @@ case DXGI_FORMAT_R16G16B16A16_FLOAT: { pDstFormats[n++] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; } break; - - default: - Logger::warn(str::format("VkD3DPresenter: Unknown format: ", m_desc.Format)); } return n; diff -Nru dxvk-0.95+ds1/src/d3d11/d3d11_texture.cpp dxvk-0.96+ds1/src/d3d11/d3d11_texture.cpp --- dxvk-0.95+ds1/src/d3d11/d3d11_texture.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/d3d11/d3d11_texture.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -78,11 +78,20 @@ imageInfo.access |= VK_ACCESS_SHADER_READ_BIT; } - if (m_desc.BindFlags & D3D11_BIND_RENDER_TARGET) + if (m_desc.BindFlags & D3D11_BIND_RENDER_TARGET) { imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT + | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + } - if (m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) + if (m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) { imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT + | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + } if (m_desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS && !noUav) { imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT; diff -Nru dxvk-0.95+ds1/src/dxbc/dxbc_analysis.cpp dxvk-0.96+ds1/src/dxbc/dxbc_analysis.cpp --- dxvk-0.95+ds1/src/dxbc/dxbc_analysis.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxbc/dxbc_analysis.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -7,9 +7,11 @@ const DxbcProgramInfo& programInfo, const Rc& isgn, const Rc& osgn, + const Rc& psgn, DxbcAnalysisInfo& analysis) : m_isgn (isgn), m_osgn (osgn), + m_psgn (psgn), m_analysis(&analysis) { // Get number of clipping and culling planes from the // input and output signatures. We will need this to diff -Nru dxvk-0.95+ds1/src/dxbc/dxbc_analysis.h dxvk-0.96+ds1/src/dxbc/dxbc_analysis.h --- dxvk-0.95+ds1/src/dxbc/dxbc_analysis.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxbc/dxbc_analysis.h 2019-01-26 17:41:48.000000000 +0000 @@ -58,6 +58,7 @@ const DxbcProgramInfo& programInfo, const Rc& isgn, const Rc& osgn, + const Rc& psgn, DxbcAnalysisInfo& analysis); ~DxbcAnalyzer(); @@ -73,6 +74,7 @@ Rc m_isgn; Rc m_osgn; + Rc m_psgn; DxbcAnalysisInfo* m_analysis = nullptr; diff -Nru dxvk-0.95+ds1/src/dxbc/dxbc_chunk_isgn.cpp dxvk-0.96+ds1/src/dxbc/dxbc_chunk_isgn.cpp --- dxvk-0.95+ds1/src/dxbc/dxbc_chunk_isgn.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxbc/dxbc_chunk_isgn.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -76,6 +76,14 @@ } + uint32_t DxbcIsgn::maxRegisterCount() const { + uint32_t result = 0; + for (auto e = this->begin(); e != this->end(); e++) + result = std::max(result, e->registerId + 1); + return result; + } + + bool DxbcIsgn::compareSemanticNames( const std::string& a, const std::string& b) const { if (a.size() != b.size()) diff -Nru dxvk-0.95+ds1/src/dxbc/dxbc_chunk_isgn.h dxvk-0.96+ds1/src/dxbc/dxbc_chunk_isgn.h --- dxvk-0.95+ds1/src/dxbc/dxbc_chunk_isgn.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxbc/dxbc_chunk_isgn.h 2019-01-26 17:41:48.000000000 +0000 @@ -52,6 +52,8 @@ DxbcRegMask regMask( uint32_t registerId) const; + uint32_t maxRegisterCount() const; + private: std::vector m_entries; diff -Nru dxvk-0.95+ds1/src/dxbc/dxbc_compiler.cpp dxvk-0.96+ds1/src/dxbc/dxbc_compiler.cpp --- dxvk-0.95+ds1/src/dxbc/dxbc_compiler.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxbc/dxbc_compiler.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -15,11 +15,13 @@ const DxbcProgramInfo& programInfo, const Rc& isgn, const Rc& osgn, + const Rc& psgn, const DxbcAnalysisInfo& analysis) : m_moduleInfo (moduleInfo), m_programInfo(programInfo), m_isgn (isgn), m_osgn (osgn), + m_psgn (psgn), m_analysis (&analysis) { // Declare an entry point ID. We'll need it during the // initialization phase where the execution mode is set. @@ -6853,6 +6855,9 @@ void DxbcCompiler::emitHsOutputSetup() { uint32_t outputPerPatch = emitTessInterfacePerPatch(spv::StorageClassOutput); + if (!outputPerPatch) + return; + uint32_t vecType = getVectorTypeId({ DxbcScalarType::Float32, 4 }); uint32_t srcPtrType = m_module.defPointerType(vecType, spv::StorageClassPrivate); @@ -6879,8 +6884,13 @@ if (storageClass == spv::StorageClassOutput) name = "oPatch"; + uint32_t arrLen = m_psgn != nullptr ? m_psgn->maxRegisterCount() : 0; + + if (!arrLen) + return 0; + uint32_t vecType = m_module.defVectorType (m_module.defFloatType(32), 4); - uint32_t arrType = m_module.defArrayType (vecType, m_module.constu32(32)); + uint32_t arrType = m_module.defArrayType (vecType, m_module.constu32(arrLen)); uint32_t ptrType = m_module.defPointerType(arrType, storageClass); uint32_t varId = m_module.newVar (ptrType, storageClass); @@ -6900,14 +6910,25 @@ uint32_t DxbcCompiler::emitTessInterfacePerVertex(spv::StorageClass storageClass, uint32_t vertexCount) { const bool isInput = storageClass == spv::StorageClassInput; + uint32_t arrLen = isInput + ? (m_isgn != nullptr ? m_isgn->maxRegisterCount() : 0) + : (m_osgn != nullptr ? m_osgn->maxRegisterCount() : 0); + + if (!arrLen) + return 0; + + uint32_t locIdx = m_psgn != nullptr + ? m_psgn->maxRegisterCount() + : 0; + uint32_t vecType = m_module.defVectorType (m_module.defFloatType(32), 4); - uint32_t arrTypeInner = m_module.defArrayType (vecType, m_module.constu32(32)); + uint32_t arrTypeInner = m_module.defArrayType (vecType, m_module.constu32(arrLen)); uint32_t arrTypeOuter = m_module.defArrayType (arrTypeInner, m_module.constu32(vertexCount)); uint32_t ptrType = m_module.defPointerType(arrTypeOuter, storageClass); uint32_t varId = m_module.newVar (ptrType, storageClass); m_module.setDebugName (varId, isInput ? "vVertex" : "oVertex"); - m_module.decorateLocation (varId, 0); + m_module.decorateLocation (varId, locIdx); if (storageClass != spv::StorageClassPrivate) m_entryPointInterfaces.push_back(varId); diff -Nru dxvk-0.95+ds1/src/dxbc/dxbc_compiler.h dxvk-0.96+ds1/src/dxbc/dxbc_compiler.h --- dxvk-0.95+ds1/src/dxbc/dxbc_compiler.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxbc/dxbc_compiler.h 2019-01-26 17:41:48.000000000 +0000 @@ -377,6 +377,7 @@ const DxbcProgramInfo& programInfo, const Rc& isgn, const Rc& osgn, + const Rc& psgn, const DxbcAnalysisInfo& analysis); ~DxbcCompiler(); @@ -410,6 +411,7 @@ Rc m_isgn; Rc m_osgn; + Rc m_psgn; const DxbcAnalysisInfo* m_analysis; diff -Nru dxvk-0.95+ds1/src/dxbc/dxbc_module.cpp dxvk-0.96+ds1/src/dxbc/dxbc_module.cpp --- dxvk-0.95+ds1/src/dxbc/dxbc_module.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxbc/dxbc_module.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -28,6 +28,9 @@ if ((tag == "OSGN") || (tag == "OSG5") || (tag == "OSG1")) m_osgnChunk = new DxbcIsgn(chunkReader, tag); + + if ((tag == "PCSG") || (tag == "PSG1")) + m_psgnChunk = new DxbcIsgn(chunkReader, tag); } } @@ -48,7 +51,7 @@ DxbcAnalyzer analyzer(moduleInfo, m_shexChunk->programInfo(), m_isgnChunk, m_osgnChunk, - analysisInfo); + m_psgnChunk, analysisInfo); this->runAnalyzer(analyzer, m_shexChunk->slice()); @@ -56,7 +59,7 @@ fileName, moduleInfo, m_shexChunk->programInfo(), m_isgnChunk, m_osgnChunk, - analysisInfo); + m_psgnChunk, analysisInfo); this->runCompiler(compiler, m_shexChunk->slice()); @@ -76,7 +79,7 @@ fileName, moduleInfo, DxbcProgramType::GeometryShader, m_osgnChunk, m_osgnChunk, - analysisInfo); + m_psgnChunk, analysisInfo); compiler.processXfbPassthrough(); return compiler.finalize(); diff -Nru dxvk-0.95+ds1/src/dxbc/dxbc_module.h dxvk-0.96+ds1/src/dxbc/dxbc_module.h --- dxvk-0.95+ds1/src/dxbc/dxbc_module.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxbc/dxbc_module.h 2019-01-26 17:41:48.000000000 +0000 @@ -80,6 +80,7 @@ Rc m_isgnChunk; Rc m_osgnChunk; + Rc m_psgnChunk; Rc m_shexChunk; void runAnalyzer( diff -Nru dxvk-0.95+ds1/src/dxgi/dxgi_options.cpp dxvk-0.96+ds1/src/dxgi/dxgi_options.cpp --- dxvk-0.95+ds1/src/dxgi/dxgi_options.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxgi/dxgi_options.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -28,9 +28,6 @@ DxgiOptions::DxgiOptions(const Config& config) { - this->deferSurfaceCreation = config.getOption ("dxgi.deferSurfaceCreation", false); - this->maxFrameLatency = config.getOption ("dxgi.maxFrameLatency", 0); - // Fetch these as a string representing a hexadecimal number and parse it. this->customVendorId = parsePciId(config.getOption("dxgi.customVendorId")); this->customDeviceId = parsePciId(config.getOption("dxgi.customDeviceId")); diff -Nru dxvk-0.95+ds1/src/dxgi/dxgi_options.h dxvk-0.96+ds1/src/dxgi/dxgi_options.h --- dxvk-0.95+ds1/src/dxgi/dxgi_options.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxgi/dxgi_options.h 2019-01-26 17:41:48.000000000 +0000 @@ -17,15 +17,6 @@ struct DxgiOptions { DxgiOptions(const Config& config); - /// Defer surface creation until first present call. This - /// fixes issues with games that create multiple swap chains - /// for a single window that may interfere with each other. - bool deferSurfaceCreation; - - /// Override maximum frame latency if the app specifies - /// a higher value. May help with frame timing issues. - int32_t maxFrameLatency; - /// Override PCI vendor and device IDs reported to the /// application. This may make apps think they are running /// on a different GPU than they do and behave differently. diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_barrier.cpp dxvk-0.96+ds1/src/dxvk/dxvk_barrier.cpp --- dxvk-0.95+ds1/src/dxvk/dxvk_barrier.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_barrier.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -16,6 +16,10 @@ m_srcStages |= srcStages; m_dstStages |= dstStages; + if (srcStages == VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT + || dstStages == VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT) + access.set(DxvkAccess::Write); + if (access.test(DxvkAccess::Write)) { VkBufferMemoryBarrier barrier; barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; @@ -48,7 +52,9 @@ m_srcStages |= srcStages; m_dstStages |= dstStages; - if (srcLayout != dstLayout) + if (srcStages == VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT + || dstStages == VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT + || srcLayout != dstLayout) access.set(DxvkAccess::Write); if (access.test(DxvkAccess::Write)) { @@ -69,12 +75,25 @@ m_imgSlices.push_back({ image.ptr(), subresources, access }); } + + + void DxvkBarrierSet::accessMemory( + VkPipelineStageFlags srcStages, + VkAccessFlags srcAccess, + VkPipelineStageFlags dstStages, + VkAccessFlags dstAccess) { + m_srcStages |= srcStages; + m_dstStages |= dstStages; + + m_srcAccess |= srcAccess; + m_dstAccess |= dstAccess; + } bool DxvkBarrierSet::isBufferDirty( const DxvkBufferSliceHandle& bufSlice, DxvkAccessFlags bufAccess) { - bool result = false; + bool result = m_srcAccess || m_dstAccess; for (uint32_t i = 0; i < m_bufSlices.size() && !result; i++) { const DxvkBufferSliceHandle& dstSlice = m_bufSlices[i].slice; @@ -92,7 +111,8 @@ const Rc& image, const VkImageSubresourceRange& imgSubres, DxvkAccessFlags imgAccess) { - bool result = false; + bool result = (m_srcStages & image->info().stages) + && (m_srcAccess & image->info().access); for (uint32_t i = 0; i < m_imgSlices.size() && !result; i++) { const VkImageSubresourceRange& dstSubres = m_imgSlices[i].subres; @@ -109,16 +129,26 @@ void DxvkBarrierSet::recordCommands(const Rc& commandList) { - if ((m_srcStages | m_dstStages) != 0) { + if (m_srcStages | m_dstStages) { VkPipelineStageFlags srcFlags = m_srcStages; VkPipelineStageFlags dstFlags = m_dstStages; - if (srcFlags == 0) srcFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - if (dstFlags == 0) dstFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + if (!srcFlags) srcFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + if (!dstFlags) dstFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + + VkMemoryBarrier memBarrier; + memBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + memBarrier.pNext = nullptr; + memBarrier.srcAccessMask = m_srcAccess; + memBarrier.dstAccessMask = m_dstAccess; + + VkMemoryBarrier* pMemBarrier = nullptr; + if (m_srcAccess | m_dstAccess) + pMemBarrier = &memBarrier; commandList->cmdPipelineBarrier( srcFlags, dstFlags, 0, - m_memBarriers.size(), m_memBarriers.data(), + pMemBarrier ? 1 : 0, pMemBarrier, m_bufBarriers.size(), m_bufBarriers.data(), m_imgBarriers.size(), m_imgBarriers.data()); @@ -131,7 +161,6 @@ m_srcStages = 0; m_dstStages = 0; - m_memBarriers.resize(0); m_bufBarriers.resize(0); m_imgBarriers.resize(0); diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_barrier.h dxvk-0.96+ds1/src/dxvk/dxvk_barrier.h --- dxvk-0.95+ds1/src/dxvk/dxvk_barrier.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_barrier.h 2019-01-26 17:41:48.000000000 +0000 @@ -37,6 +37,12 @@ VkPipelineStageFlags dstStages, VkAccessFlags dstAccess); + void accessMemory( + VkPipelineStageFlags srcStages, + VkAccessFlags srcAccess, + VkPipelineStageFlags dstStages, + VkAccessFlags dstAccess); + bool isBufferDirty( const DxvkBufferSliceHandle& bufSlice, DxvkAccessFlags bufAccess); @@ -66,8 +72,10 @@ VkPipelineStageFlags m_srcStages = 0; VkPipelineStageFlags m_dstStages = 0; + + VkAccessFlags m_srcAccess = 0; + VkAccessFlags m_dstAccess = 0; - std::vector m_memBarriers; std::vector m_bufBarriers; std::vector m_imgBarriers; diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_buffer.cpp dxvk-0.96+ds1/src/dxvk/dxvk_buffer.cpp --- dxvk-0.95+ds1/src/dxvk/dxvk_buffer.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_buffer.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -143,7 +143,7 @@ const Rc& buffer, const DxvkBufferViewCreateInfo& info) : m_vkd(vkd), m_info(info), m_buffer(buffer), - m_bufferSlice (m_buffer->getSliceHandle()), + m_bufferSlice (getSliceHandle()), m_bufferView (createBufferView(m_bufferSlice)) { } @@ -188,13 +188,14 @@ } - void DxvkBufferView::updateBufferView() { + void DxvkBufferView::updateBufferView( + const DxvkBufferSliceHandle& slice) { if (m_views.empty()) m_views.insert({ m_bufferSlice, m_bufferView }); - m_bufferSlice = m_buffer->getSliceHandle(); - auto entry = m_views.find(m_bufferSlice); - + m_bufferSlice = slice; + + auto entry = m_views.find(slice); if (entry != m_views.end()) { m_bufferView = entry->second; } else { diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_buffer.h dxvk-0.96+ds1/src/dxvk/dxvk_buffer.h --- dxvk-0.95+ds1/src/dxvk/dxvk_buffer.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_buffer.h 2019-01-26 17:41:48.000000000 +0000 @@ -515,8 +515,10 @@ * prior to using the buffer view handle. */ void updateView() { - if (!m_bufferSlice.eq(m_buffer->getSliceHandle())) - this->updateBufferView(); + DxvkBufferSliceHandle slice = getSliceHandle(); + + if (!m_bufferSlice.eq(slice)) + this->updateBufferView(slice); } private: @@ -536,7 +538,8 @@ VkBufferView createBufferView( const DxvkBufferSliceHandle& slice); - void updateBufferView(); + void updateBufferView( + const DxvkBufferSliceHandle& slice); }; diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_constant_state.h dxvk-0.96+ds1/src/dxvk/dxvk_constant_state.h --- dxvk-0.95+ds1/src/dxvk/dxvk_constant_state.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_constant_state.h 2019-01-26 17:41:48.000000000 +0000 @@ -27,6 +27,30 @@ || this->b != other.b || this->a != other.a; } }; + + + /** + * \brief Depth bias + * + * Stores depth bias values. + */ + struct DxvkDepthBias { + float depthBiasConstant; + float depthBiasSlope; + float depthBiasClamp; + + bool operator == (const DxvkDepthBias& other) const { + return depthBiasConstant == other.depthBiasConstant + && depthBiasSlope == other.depthBiasSlope + && depthBiasClamp == other.depthBiasClamp; + } + + bool operator != (const DxvkDepthBias& other) const { + return depthBiasConstant != other.depthBiasConstant + || depthBiasSlope != other.depthBiasSlope + || depthBiasClamp != other.depthBiasClamp; + } + }; /** @@ -53,11 +77,8 @@ VkPolygonMode polygonMode; VkCullModeFlags cullMode; VkFrontFace frontFace; - VkBool32 depthClampEnable; + VkBool32 depthClipEnable; VkBool32 depthBiasEnable; - float depthBiasConstant; - float depthBiasClamp; - float depthBiasSlope; VkSampleCountFlags sampleCount; }; diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_context.cpp dxvk-0.96+ds1/src/dxvk/dxvk_context.cpp --- dxvk-0.95+ds1/src/dxvk/dxvk_context.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_context.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -48,6 +48,10 @@ DxvkContextFlag::GpDirtyVertexBuffers, DxvkContextFlag::GpDirtyIndexBuffer, DxvkContextFlag::GpDirtyXfbBuffers, + DxvkContextFlag::GpDirtyBlendConstants, + DxvkContextFlag::GpDirtyStencilRef, + DxvkContextFlag::GpDirtyViewport, + DxvkContextFlag::GpDirtyDepthBias, DxvkContextFlag::CpDirtyPipeline, DxvkContextFlag::CpDirtyPipelineState, DxvkContextFlag::CpDirtyResources, @@ -93,17 +97,17 @@ void DxvkContext::bindRenderTargets( const DxvkRenderTargets& targets, bool spill) { - m_state.om.renderTargets = targets; - // If necessary, perform clears on the active render targets if (m_flags.test(DxvkContextFlag::GpClearRenderTargets)) - this->startRenderPass(); + this->clearRenderPass(); // Set up default render pass ops + m_state.om.renderTargets = targets; + this->resetRenderPassOps( m_state.om.renderTargets, m_state.om.renderPassOps); - + if (m_state.om.framebuffer == nullptr || !m_state.om.framebuffer->hasTargets(targets)) { // Create a new framebuffer object next // time we start rendering something @@ -288,8 +292,12 @@ this->spillRenderPass(); this->unbindComputePipeline(); + // The view range might have been invalidated, so + // we need to make sure the handle is up to date + bufferView->updateView(); + auto bufferSlice = bufferView->getSliceHandle(); - + if (m_barriers.isBufferDirty(bufferSlice, DxvkAccess::Write)) m_barriers.recordCommands(m_cmd); @@ -533,6 +541,12 @@ if (attachmentIndex < 0) { this->spillRenderPass(); + + if (m_barriers.isImageDirty( + imageView->image(), + imageView->subresources(), + DxvkAccess::Write)) + m_barriers.recordCommands(m_cmd); // Set up and bind a temporary framebuffer DxvkRenderTargets attachments; @@ -541,10 +555,12 @@ if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) { attachments.color[0].view = imageView; attachments.color[0].layout = imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + ops.colorOps[0] = colorOp; } else { attachments.depth.view = imageView; attachments.depth.layout = imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + ops.depthOps = depthOp; } @@ -552,6 +568,15 @@ m_device->createFramebuffer(attachments), ops, 1, &clearValue); this->renderPassUnbindFramebuffer(); + + m_barriers.accessImage( + imageView->image(), + imageView->subresources(), + imageView->imageInfo().layout, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, + imageView->imageInfo().layout, + imageView->imageInfo().stages, + imageView->imageInfo().access); } else if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { // Clear the attachment in quesion. For color images, // the attachment index for the current subpass is @@ -1126,7 +1151,7 @@ uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) { - this->commitGraphicsState(); + this->commitGraphicsState(false); if (this->validateGraphicsState()) { m_cmd->cmdDraw( @@ -1144,7 +1169,7 @@ VkDeviceSize offset, uint32_t count, uint32_t stride) { - this->commitGraphicsState(); + this->commitGraphicsState(false); if (this->validateGraphicsState()) { auto descriptor = m_state.id.argBuffer.getDescriptor(); @@ -1168,7 +1193,7 @@ uint32_t firstIndex, uint32_t vertexOffset, uint32_t firstInstance) { - this->commitGraphicsState(); + this->commitGraphicsState(true); if (this->validateGraphicsState()) { m_cmd->cmdDrawIndexed( @@ -1187,7 +1212,7 @@ VkDeviceSize offset, uint32_t count, uint32_t stride) { - this->commitGraphicsState(); + this->commitGraphicsState(true); if (this->validateGraphicsState()) { auto descriptor = m_state.id.argBuffer.getDescriptor(); @@ -1209,7 +1234,7 @@ const DxvkBufferSlice& counterBuffer, uint32_t counterDivisor, uint32_t counterBias) { - this->commitGraphicsState(); + this->commitGraphicsState(false); if (this->validateGraphicsState()) { auto physSlice = counterBuffer.getSliceHandle(); @@ -1588,18 +1613,27 @@ void DxvkContext::setBlendConstants( - const DxvkBlendConstants& blendConstants) { - if (m_state.om.blendConstants != blendConstants) { - m_state.om.blendConstants = blendConstants; + DxvkBlendConstants blendConstants) { + if (m_state.dyn.blendConstants != blendConstants) { + m_state.dyn.blendConstants = blendConstants; m_flags.set(DxvkContextFlag::GpDirtyBlendConstants); } } + void DxvkContext::setDepthBias( + DxvkDepthBias depthBias) { + if (m_state.dyn.depthBias != depthBias) { + m_state.dyn.depthBias = depthBias; + m_flags.set(DxvkContextFlag::GpDirtyDepthBias); + } + } + + void DxvkContext::setStencilReference( - const uint32_t reference) { - if (m_state.om.stencilReference != reference) { - m_state.om.stencilReference = reference; + uint32_t reference) { + if (m_state.dyn.stencilReference != reference) { + m_state.dyn.stencilReference = reference; m_flags.set(DxvkContextFlag::GpDirtyStencilRef); } } @@ -1648,20 +1682,14 @@ void DxvkContext::setRasterizerState(const DxvkRasterizerState& rs) { - m_state.gp.state.rsDepthClampEnable = rs.depthClampEnable; + m_state.gp.state.rsDepthClipEnable = rs.depthClipEnable; m_state.gp.state.rsDepthBiasEnable = rs.depthBiasEnable; m_state.gp.state.rsPolygonMode = rs.polygonMode; m_state.gp.state.rsCullMode = rs.cullMode; m_state.gp.state.rsFrontFace = rs.frontFace; m_state.gp.state.rsSampleCount = rs.sampleCount; - m_state.ds.depthBiasConstant = rs.depthBiasConstant; - m_state.ds.depthBiasClamp = rs.depthBiasClamp; - m_state.ds.depthBiasSlope = rs.depthBiasSlope; - - m_flags.set( - DxvkContextFlag::GpDirtyPipelineState, - DxvkContextFlag::GpDirtyDepthBias); + m_flags.set(DxvkContextFlag::GpDirtyPipelineState); } @@ -1743,6 +1771,12 @@ if (attachmentIndex < 0) { this->spillRenderPass(); + if (m_barriers.isImageDirty( + imageView->image(), + imageView->subresources(), + DxvkAccess::Write)) + m_barriers.recordCommands(m_cmd); + // Set up a temporary framebuffer DxvkRenderTargets attachments; DxvkRenderPassOps ops; @@ -1750,9 +1784,21 @@ if (imageView->info().aspect & VK_IMAGE_ASPECT_COLOR_BIT) { attachments.color[0].view = imageView; attachments.color[0].layout = imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + ops.colorOps[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + ops.colorOps[0].loadLayout = imageView->imageInfo().layout; + ops.colorOps[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + ops.colorOps[0].storeLayout = imageView->imageInfo().layout; } else { attachments.depth.view = imageView; attachments.depth.layout = imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + + ops.depthOps.loadOpD = VK_ATTACHMENT_LOAD_OP_LOAD; + ops.depthOps.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD; + ops.depthOps.loadLayout = imageView->imageInfo().layout; + ops.depthOps.storeOpD = VK_ATTACHMENT_STORE_OP_STORE; + ops.depthOps.storeOpS = VK_ATTACHMENT_STORE_OP_STORE; + ops.depthOps.storeLayout = imageView->imageInfo().layout; } // We cannot leverage render pass clears @@ -1760,6 +1806,15 @@ this->renderPassBindFramebuffer( m_device->createFramebuffer(attachments), ops, 0, nullptr); + + m_barriers.accessImage( + imageView->image(), + imageView->subresources(), + imageView->imageInfo().layout, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, + imageView->imageInfo().layout, + imageView->imageInfo().stages, + imageView->imageInfo().access); } // Perform the actual clear operation @@ -2329,6 +2384,8 @@ m_flags.set(DxvkContextFlag::GpRenderPassBound); m_flags.clr(DxvkContextFlag::GpClearRenderTargets); + m_barriers.recordCommands(m_cmd); + this->renderPassBindFramebuffer( m_state.om.framebuffer, m_state.om.renderPassOps, @@ -2350,7 +2407,7 @@ void DxvkContext::spillRenderPass() { if (m_flags.test(DxvkContextFlag::GpClearRenderTargets)) - this->startRenderPass(); + this->clearRenderPass(); if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { m_flags.clr(DxvkContextFlag::GpRenderPassBound); @@ -2366,6 +2423,52 @@ m_flags.clr(DxvkContextFlag::GpDirtyXfbCounters); } } + + + void DxvkContext::clearRenderPass() { + if (m_flags.test(DxvkContextFlag::GpClearRenderTargets)) { + m_flags.clr(DxvkContextFlag::GpClearRenderTargets); + + bool flushBarriers = false; + + for (uint32_t i = 0; i < m_state.om.framebuffer->numAttachments(); i++) { + const DxvkAttachment& attachment = m_state.om.framebuffer->getAttachment(i); + + flushBarriers |= m_barriers.isImageDirty( + attachment.view->image(), + attachment.view->subresources(), + DxvkAccess::Write); + } + + if (flushBarriers) + m_barriers.recordCommands(m_cmd); + + this->renderPassBindFramebuffer( + m_state.om.framebuffer, + m_state.om.renderPassOps, + m_state.om.clearValues.size(), + m_state.om.clearValues.data()); + + this->resetRenderPassOps( + m_state.om.renderTargets, + m_state.om.renderPassOps); + + this->renderPassUnbindFramebuffer(); + + for (uint32_t i = 0; i < m_state.om.framebuffer->numAttachments(); i++) { + const DxvkAttachment& attachment = m_state.om.framebuffer->getAttachment(i); + + m_barriers.accessImage( + attachment.view->image(), + attachment.view->subresources(), + attachment.view->imageInfo().layout, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, + attachment.view->imageInfo().layout, + attachment.view->imageInfo().stages, + attachment.view->imageInfo().access); + } + } + } void DxvkContext::renderPassBindFramebuffer( @@ -2388,8 +2491,6 @@ info.clearValueCount = clearValueCount; info.pClearValues = clearValues; - m_barriers.recordCommands(m_cmd); - m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE); @@ -2412,6 +2513,25 @@ void DxvkContext::resetRenderPassOps( const DxvkRenderTargets& renderTargets, DxvkRenderPassOps& renderPassOps) { + renderPassOps.barrier.srcStages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + renderPassOps.barrier.srcAccess = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT + | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT + | VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT + | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT + | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT + | VK_ACCESS_INDIRECT_COMMAND_READ_BIT + | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT + | VK_ACCESS_INDEX_READ_BIT + | VK_ACCESS_UNIFORM_READ_BIT + | VK_ACCESS_SHADER_READ_BIT + | VK_ACCESS_SHADER_WRITE_BIT; + renderPassOps.barrier.dstStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + renderPassOps.barrier.dstAccess = renderPassOps.barrier.srcAccess + | VK_ACCESS_TRANSFER_READ_BIT + | VK_ACCESS_TRANSFER_WRITE_BIT; + renderPassOps.depthOps = renderTargets.depth.view != nullptr ? DxvkDepthAttachmentOps { VK_ATTACHMENT_LOAD_OP_LOAD, @@ -2551,7 +2671,11 @@ DxvkContextFlag::GpDirtyResources, DxvkContextFlag::GpDirtyVertexBuffers, DxvkContextFlag::GpDirtyIndexBuffer, - DxvkContextFlag::GpDirtyXfbBuffers); + DxvkContextFlag::GpDirtyXfbBuffers, + DxvkContextFlag::GpDirtyBlendConstants, + DxvkContextFlag::GpDirtyStencilRef, + DxvkContextFlag::GpDirtyViewport, + DxvkContextFlag::GpDirtyDepthBias); m_gpActivePipeline = VK_NULL_HANDLE; } @@ -2582,6 +2706,7 @@ this->pauseTransformFeedback(); + // Fix up vertex binding strides for unbound buffers for (uint32_t i = 0; i < m_state.gp.state.ilBindingCount; i++) { const uint32_t binding = m_state.gp.state.ilBindings[i].binding; @@ -2594,6 +2719,25 @@ for (uint32_t i = m_state.gp.state.ilBindingCount; i < MaxNumVertexBindings; i++) m_state.gp.state.ilBindings[i].stride = 0; + // Check which dynamic states need to be active. States that + // are not dynamic will be invalidated in the command buffer. + m_flags.clr(DxvkContextFlag::GpDynamicBlendConstants, + DxvkContextFlag::GpDynamicDepthBias, + DxvkContextFlag::GpDynamicStencilRef); + + m_flags.set(m_state.gp.state.useDynamicBlendConstants() + ? DxvkContextFlag::GpDynamicBlendConstants + : DxvkContextFlag::GpDirtyBlendConstants); + + m_flags.set(m_state.gp.state.useDynamicDepthBias() + ? DxvkContextFlag::GpDynamicDepthBias + : DxvkContextFlag::GpDirtyDepthBias); + + m_flags.set(m_state.gp.state.useDynamicStencilRef() + ? DxvkContextFlag::GpDynamicStencilRef + : DxvkContextFlag::GpDirtyStencilRef); + + // Retrieve and bind actual Vulkan pipeline handle m_gpActivePipeline = m_state.gp.pipeline != nullptr && m_state.om.framebuffer != nullptr ? m_state.gp.pipeline->getPipelineHandle(m_state.gp.state, m_state.om.framebuffer->getRenderPass()) @@ -2604,12 +2748,6 @@ VK_PIPELINE_BIND_POINT_GRAPHICS, m_gpActivePipeline); } - - m_flags.set( - DxvkContextFlag::GpDirtyBlendConstants, - DxvkContextFlag::GpDirtyStencilRef, - DxvkContextFlag::GpDirtyViewport, - DxvkContextFlag::GpDirtyDepthBias); } } @@ -3004,29 +3142,37 @@ return; if (m_flags.test(DxvkContextFlag::GpDirtyViewport)) { + m_flags.clr(DxvkContextFlag::GpDirtyViewport); + uint32_t viewportCount = m_state.gp.state.rsViewportCount; m_cmd->cmdSetViewport(0, viewportCount, m_state.vp.viewports.data()); m_cmd->cmdSetScissor (0, viewportCount, m_state.vp.scissorRects.data()); } - if (m_flags.test(DxvkContextFlag::GpDirtyBlendConstants)) - m_cmd->cmdSetBlendConstants(&m_state.om.blendConstants.r); + if (m_flags.all(DxvkContextFlag::GpDirtyBlendConstants, + DxvkContextFlag::GpDynamicBlendConstants)) { + m_flags.clr(DxvkContextFlag::GpDirtyBlendConstants); + m_cmd->cmdSetBlendConstants(&m_state.dyn.blendConstants.r); + } + + if (m_flags.all(DxvkContextFlag::GpDirtyStencilRef, + DxvkContextFlag::GpDynamicStencilRef)) { + m_flags.clr(DxvkContextFlag::GpDirtyStencilRef); - if (m_flags.test(DxvkContextFlag::GpDirtyStencilRef)) - m_cmd->cmdSetStencilReference(VK_STENCIL_FRONT_AND_BACK, m_state.om.stencilReference); + m_cmd->cmdSetStencilReference( + VK_STENCIL_FRONT_AND_BACK, + m_state.dyn.stencilReference); + } - if (m_flags.test(DxvkContextFlag::GpDirtyDepthBias)) { + if (m_flags.all(DxvkContextFlag::GpDirtyDepthBias, + DxvkContextFlag::GpDynamicDepthBias)) { + m_flags.clr(DxvkContextFlag::GpDirtyDepthBias); + m_cmd->cmdSetDepthBias( - m_state.ds.depthBiasConstant, - m_state.ds.depthBiasClamp, - m_state.ds.depthBiasSlope); + m_state.dyn.depthBias.depthBiasConstant, + m_state.dyn.depthBias.depthBiasClamp, + m_state.dyn.depthBias.depthBiasSlope); } - - m_flags.clr( - DxvkContextFlag::GpDirtyBlendConstants, - DxvkContextFlag::GpDirtyStencilRef, - DxvkContextFlag::GpDirtyViewport, - DxvkContextFlag::GpDirtyDepthBias); } @@ -3047,10 +3193,11 @@ void DxvkContext::commitComputeState() { - if (m_flags.any( - DxvkContextFlag::GpRenderPassBound, - DxvkContextFlag::GpClearRenderTargets)) + if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) this->spillRenderPass(); + + if (m_flags.test(DxvkContextFlag::GpClearRenderTargets)) + this->clearRenderPass(); if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) this->updateComputePipeline(); @@ -3070,7 +3217,7 @@ } - void DxvkContext::commitGraphicsState() { + void DxvkContext::commitGraphicsState(bool indexed) { if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) this->updateFramebuffer(); @@ -3080,7 +3227,7 @@ if (m_flags.test(DxvkContextFlag::GpDirtyPipeline)) this->updateGraphicsPipeline(); - if (m_flags.test(DxvkContextFlag::GpDirtyIndexBuffer)) + if (m_flags.test(DxvkContextFlag::GpDirtyIndexBuffer) && indexed) this->updateIndexBufferBinding(); if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_context.h dxvk-0.96+ds1/src/dxvk/dxvk_context.h --- dxvk-0.95+ds1/src/dxvk/dxvk_context.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_context.h 2019-01-26 17:41:48.000000000 +0000 @@ -674,7 +674,17 @@ * \param [in] blendConstants Blend constants */ void setBlendConstants( - const DxvkBlendConstants& blendConstants); + DxvkBlendConstants blendConstants); + + /** + * \brief Sets depth bias + * + * Depth bias has to be enabled explicitly in + * the rasterizer state to have any effect. + * \param [in] depthBias Depth bias values + */ + void setDepthBias( + DxvkDepthBias depthBias); /** * \brief Sets stencil reference @@ -683,7 +693,7 @@ * \param [in] reference Reference value */ void setStencilReference( - const uint32_t reference); + uint32_t reference); /** * \brief Sets input assembly state @@ -834,6 +844,7 @@ void startRenderPass(); void spillRenderPass(); + void clearRenderPass(); void renderPassBindFramebuffer( const Rc& framebuffer, @@ -892,7 +903,7 @@ bool validateGraphicsState(); void commitComputeState(); - void commitGraphicsState(); + void commitGraphicsState(bool indexed); void commitComputeInitBarriers(); void commitComputePostBarriers(); diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_context_state.h dxvk-0.96+ds1/src/dxvk/dxvk_context_state.h --- dxvk-0.95+ds1/src/dxvk/dxvk_context_state.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_context_state.h 2019-01-26 17:41:48.000000000 +0000 @@ -35,16 +35,19 @@ GpDirtyXfbBuffers, ///< Transform feedback buffer bindings are out of date GpDirtyXfbCounters, ///< Counter buffer values are dirty GpDirtyBlendConstants, ///< Blend constants have changed + GpDirtyDepthBias, ///< Depth bias has changed GpDirtyStencilRef, ///< Stencil reference has changed GpDirtyViewport, ///< Viewport state has changed - GpDirtyDepthBias, ///< Depth bias has changed + GpDynamicBlendConstants, ///< Blend constants are dynamic + GpDynamicDepthBias, ///< Depth bias is dynamic + GpDynamicStencilRef, ///< Stencil reference is dynamic CpDirtyPipeline, ///< Compute pipeline binding are out of date CpDirtyPipelineState, ///< Compute pipeline needs to be recompiled CpDirtyResources, ///< Compute pipeline resource bindings are out of date CpDirtyDescriptorOffsets, ///< Compute descriptor set needs to be rebound CpDirtyDescriptorSet, ///< Compute descriptor set needs to be updated - + DirtyDrawBuffer, ///< Indirect argument buffer is dirty }; @@ -72,22 +75,12 @@ }; - struct DxvkDynamicDepthState { - float depthBiasConstant = 0.0f; - float depthBiasClamp = 0.0f; - float depthBiasSlope = 0.0f; - }; - - struct DxvkOutputMergerState { std::array clearValues = { }; DxvkRenderTargets renderTargets; DxvkRenderPassOps renderPassOps; Rc framebuffer = nullptr; - - DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }; - uint32_t stencilReference = 0; }; @@ -121,6 +114,13 @@ DxvkComputePipelineStateInfo state; Rc pipeline; }; + + + struct DxvkDynamicState { + DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }; + DxvkDepthBias depthBias = { 0.0f, 0.0f, 0.0f }; + uint32_t stencilReference = 0; + }; /** @@ -133,9 +133,9 @@ DxvkIndirectDrawState id; DxvkVertexInputState vi; DxvkViewportState vp; - DxvkDynamicDepthState ds; DxvkOutputMergerState om; DxvkXfbState xfb; + DxvkDynamicState dyn; DxvkGraphicsPipelineState gp; DxvkComputePipelineState cp; diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_graphics.cpp dxvk-0.96+ds1/src/dxvk/dxvk_graphics.cpp --- dxvk-0.95+ds1/src/dxvk/dxvk_graphics.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_graphics.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -177,13 +177,21 @@ this->logPipelineState(LogLevel::Debug, state); } - std::array dynamicStates = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR, - VK_DYNAMIC_STATE_DEPTH_BIAS, - VK_DYNAMIC_STATE_BLEND_CONSTANTS, - VK_DYNAMIC_STATE_STENCIL_REFERENCE, - }; + // Set up dynamic states as needed + std::array dynamicStates; + uint32_t dynamicStateCount = 0; + + dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT; + dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR; + + if (state.useDynamicDepthBias()) + dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_DEPTH_BIAS; + + if (state.useDynamicBlendConstants()) + dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS; + + if (state.useDynamicStencilRef()) + dynamicStates[dynamicStateCount++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; // Figure out the actual sample count to use VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT; @@ -311,7 +319,7 @@ rsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rsInfo.pNext = nullptr; rsInfo.flags = 0; - rsInfo.depthClampEnable = state.rsDepthClampEnable; + rsInfo.depthClampEnable = !state.rsDepthClipEnable; rsInfo.rasterizerDiscardEnable = rasterizedStream < 0; rsInfo.polygonMode = state.rsPolygonMode; rsInfo.cullMode = state.rsCullMode; @@ -366,7 +374,7 @@ dyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dyInfo.pNext = nullptr; dyInfo.flags = 0; - dyInfo.dynamicStateCount = dynamicStates.size(); + dyInfo.dynamicStateCount = dynamicStateCount; dyInfo.pDynamicStates = dynamicStates.data(); VkGraphicsPipelineCreateInfo info; diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_graphics.h dxvk-0.96+ds1/src/dxvk/dxvk_graphics.h --- dxvk-0.95+ds1/src/dxvk/dxvk_graphics.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_graphics.h 2019-01-26 17:41:48.000000000 +0000 @@ -27,7 +27,7 @@ using DxvkGraphicsPipelineFlags = Flags; - + /** * \brief Graphics pipeline state info * @@ -46,6 +46,28 @@ bool operator == (const DxvkGraphicsPipelineStateInfo& other) const; bool operator != (const DxvkGraphicsPipelineStateInfo& other) const; + + bool useDynamicStencilRef() const { + return dsEnableStencilTest; + } + + bool useDynamicDepthBias() const { + return rsDepthBiasEnable; + } + + bool useDynamicBlendConstants() const { + bool result = false; + + for (uint32_t i = 0; i < MaxNumRenderTargets && !result; i++) { + result |= omBlendAttachments[i].blendEnable + && (util::isBlendConstantBlendFactor(omBlendAttachments[i].srcColorBlendFactor) + || util::isBlendConstantBlendFactor(omBlendAttachments[i].dstColorBlendFactor) + || util::isBlendConstantBlendFactor(omBlendAttachments[i].srcAlphaBlendFactor) + || util::isBlendConstantBlendFactor(omBlendAttachments[i].dstAlphaBlendFactor)); + } + + return result; + } DxvkBindingMask bsBindingMask; @@ -59,7 +81,7 @@ VkVertexInputBindingDescription ilBindings[DxvkLimits::MaxNumVertexBindings]; uint32_t ilDivisors[DxvkLimits::MaxNumVertexBindings]; - VkBool32 rsDepthClampEnable; + VkBool32 rsDepthClipEnable; VkBool32 rsDepthBiasEnable; VkPolygonMode rsPolygonMode; VkCullModeFlags rsCullMode; diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_instance.cpp dxvk-0.96+ds1/src/dxvk/dxvk_instance.cpp --- dxvk-0.95+ds1/src/dxvk/dxvk_instance.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_instance.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -102,7 +102,7 @@ appInfo.pApplicationName = appName.c_str(); appInfo.applicationVersion = 0; appInfo.pEngineName = "DXVK"; - appInfo.engineVersion = VK_MAKE_VERSION(0, 9, 5); + appInfo.engineVersion = VK_MAKE_VERSION(0, 9, 6); appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0); VkInstanceCreateInfo info; diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_renderpass.cpp dxvk-0.96+ds1/src/dxvk/dxvk_renderpass.cpp --- dxvk-0.95+ds1/src/dxvk/dxvk_renderpass.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_renderpass.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -121,44 +121,39 @@ if (m_format.depth.format == VK_FORMAT_UNDEFINED) subpass.pDepthStencilAttachment = nullptr; - const std::array subpassDeps = {{ - { VK_SUBPASS_EXTERNAL, 0, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, - 0, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, 0 }, - { 0, 0, + std::array subpassDeps; + uint32_t subpassDepCount = 0; + + if (ops.barrier.srcStages & ( + VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT | + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT)) { + subpassDeps[subpassDepCount++] = { 0, 0, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, /* XXX */ VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT, - VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT, 0 }, - { 0, 0, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT, 0 }; + } + + if (ops.barrier.srcStages & ( + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT | + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT)) { + subpassDeps[subpassDepCount++] = { 0, 0, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, - VK_ACCESS_SHADER_READ_BIT, 0 }, - { 0, VK_SUBPASS_EXTERNAL, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT | - VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT | - VK_ACCESS_SHADER_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_HOST_READ_BIT | - VK_ACCESS_INDEX_READ_BIT | - VK_ACCESS_INDIRECT_COMMAND_READ_BIT | - VK_ACCESS_SHADER_READ_BIT | - VK_ACCESS_TRANSFER_READ_BIT | - VK_ACCESS_UNIFORM_READ_BIT | - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | - VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT, 0 }, - }}; + VK_ACCESS_SHADER_READ_BIT, 0 }; + } + + if (ops.barrier.srcStages && ops.barrier.dstStages) { + subpassDeps[subpassDepCount++] = { + 0, VK_SUBPASS_EXTERNAL, + ops.barrier.srcStages, + ops.barrier.dstStages, + ops.barrier.srcAccess, + ops.barrier.dstAccess, 0 }; + } VkRenderPassCreateInfo info; info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; @@ -168,8 +163,8 @@ info.pAttachments = attachments.data(); info.subpassCount = 1; info.pSubpasses = &subpass; - info.dependencyCount = subpassDeps.size(); - info.pDependencies = subpassDeps.data(); + info.dependencyCount = subpassDepCount; + info.pDependencies = subpassDepCount ? subpassDeps.data() : nullptr; VkRenderPass renderPass = VK_NULL_HANDLE; @@ -185,12 +180,19 @@ bool DxvkRenderPass::compareOps( const DxvkRenderPassOps& a, const DxvkRenderPassOps& b) { - bool eq = a.depthOps.loadOpD == b.depthOps.loadOpD - && a.depthOps.loadOpS == b.depthOps.loadOpS - && a.depthOps.loadLayout == b.depthOps.loadLayout - && a.depthOps.storeOpD == b.depthOps.storeOpD - && a.depthOps.storeOpS == b.depthOps.storeOpS - && a.depthOps.storeLayout == b.depthOps.storeLayout; + bool eq = a.barrier.srcStages == b.barrier.srcStages + && a.barrier.srcAccess == b.barrier.srcAccess + && a.barrier.dstStages == b.barrier.dstStages + && a.barrier.dstAccess == b.barrier.dstAccess; + + if (eq) { + eq &= a.depthOps.loadOpD == b.depthOps.loadOpD + && a.depthOps.loadOpS == b.depthOps.loadOpS + && a.depthOps.loadLayout == b.depthOps.loadLayout + && a.depthOps.storeOpD == b.depthOps.storeOpD + && a.depthOps.storeOpS == b.depthOps.storeOpS + && a.depthOps.storeLayout == b.depthOps.storeLayout; + } for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) { eq &= a.colorOps[i].loadOp == b.colorOps[i].loadOp diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_renderpass.h dxvk-0.96+ds1/src/dxvk/dxvk_renderpass.h --- dxvk-0.95+ds1/src/dxvk/dxvk_renderpass.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_renderpass.h 2019-01-26 17:41:48.000000000 +0000 @@ -67,6 +67,20 @@ /** + * \brief Render pass barrier + * + * External subpass dependency that is to be + * executed after a render pass has completed. + */ + struct DxvkRenderPassBarrier { + VkPipelineStageFlags srcStages = 0; + VkAccessFlags srcAccess = 0; + VkPipelineStageFlags dstStages = 0; + VkAccessFlags dstAccess = 0; + }; + + + /** * \brief Render pass transitions * * Stores transitions for all depth and color attachments. @@ -74,6 +88,7 @@ * from a group of render passes with the same format. */ struct DxvkRenderPassOps { + DxvkRenderPassBarrier barrier; DxvkDepthAttachmentOps depthOps; DxvkColorAttachmentOps colorOps[MaxNumRenderTargets]; }; diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_state_cache.cpp dxvk-0.96+ds1/src/dxvk/dxvk_state_cache.cpp --- dxvk-0.95+ds1/src/dxvk/dxvk_state_cache.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_state_cache.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -266,11 +266,30 @@ // The header stores the state cache version, // we need to regenerate it if it's outdated - if (!readCacheHeader(ifile)) { + DxvkStateCacheHeader newHeader; + DxvkStateCacheHeader curHeader; + + if (!readCacheHeader(ifile, curHeader)) { + Logger::warn("DXVK: Failed to read state cache header"); + return false; + } + + // Struct size hasn't changed between v2/v3 + if (curHeader.entrySize != newHeader.entrySize) { + Logger::warn("DXVK: State cache entry size changed"); + return false; + } + + // Discard caches of unsupported versions + if (curHeader.version != 2 && curHeader.version != 3) { Logger::warn("DXVK: State cache out of date"); return false; } + // Notify user about format conversion + if (curHeader.version != newHeader.version) + Logger::warn(str::format("DXVK: Updating state cache version to v", newHeader.version)); + // Read actual cache entries from the file. // If we encounter invalid entries, we should // regenerate the entire state cache file. @@ -280,6 +299,9 @@ DxvkStateCacheEntry entry; if (readCacheEntry(ifile, entry)) { + if (curHeader.version == 2) + convertEntryV2(entry); + size_t entryId = m_entries.size(); m_entries.push_back(entry); @@ -304,30 +326,31 @@ Logger::warn(str::format( "DXVK: Skipped ", numInvalidEntries, " invalid state cache entries")); + return false; } - return !numInvalidEntries; + // Rewrite entire state cache if it is outdated + return curHeader.version == newHeader.version; } bool DxvkStateCache::readCacheHeader( - std::istream& stream) const { + std::istream& stream, + DxvkStateCacheHeader& header) const { DxvkStateCacheHeader expected; - DxvkStateCacheHeader actual; - auto data = reinterpret_cast(&actual); - auto size = sizeof(actual); + auto data = reinterpret_cast(&header); + auto size = sizeof(header); if (!stream.read(data, size)) return false; for (uint32_t i = 0; i < 4; i++) { - if (expected.magic[i] != actual.magic[i]) + if (expected.magic[i] != header.magic[i]) return false; } - return expected.version == actual.version - && expected.entrySize == actual.entrySize; + return true; } @@ -359,6 +382,20 @@ } + bool DxvkStateCache::convertEntryV2( + DxvkStateCacheEntry& entry) const { + // Semantics changed: + // v2: rsDepthClampEnable + // v3: rsDepthClipEnable + entry.gpState.rsDepthClipEnable = !entry.gpState.rsDepthClipEnable; + + // Frontend changed: Depth bias + // will typically be disabled + entry.gpState.rsDepthBiasEnable = VK_FALSE; + return true; + } + + void DxvkStateCache::workerFunc() { env::setThreadName("dxvk-shader"); diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_state_cache.h dxvk-0.96+ds1/src/dxvk/dxvk_state_cache.h --- dxvk-0.95+ds1/src/dxvk/dxvk_state_cache.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_state_cache.h 2019-01-26 17:41:48.000000000 +0000 @@ -62,7 +62,7 @@ */ struct DxvkStateCacheHeader { char magic[4] = { 'D', 'X', 'V', 'K' }; - uint32_t version = 2; + uint32_t version = 3; uint32_t entrySize = sizeof(DxvkStateCacheEntry); }; @@ -190,7 +190,8 @@ bool readCacheFile(); bool readCacheHeader( - std::istream& stream) const; + std::istream& stream, + DxvkStateCacheHeader& header) const; bool readCacheEntry( std::istream& stream, @@ -200,6 +201,9 @@ std::ostream& stream, DxvkStateCacheEntry& entry) const; + bool convertEntryV2( + DxvkStateCacheEntry& entry) const; + void workerFunc(); void writerFunc(); diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_util.cpp dxvk-0.96+ds1/src/dxvk/dxvk_util.cpp --- dxvk-0.95+ds1/src/dxvk/dxvk_util.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_util.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -150,6 +150,14 @@ } + bool isBlendConstantBlendFactor(VkBlendFactor factor) { + return factor == VK_BLEND_FACTOR_CONSTANT_COLOR + || factor == VK_BLEND_FACTOR_CONSTANT_ALPHA + || factor == VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR + || factor == VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; + } + + bool isDualSourceBlendFactor(VkBlendFactor factor) { return factor == VK_BLEND_FACTOR_SRC1_COLOR || factor == VK_BLEND_FACTOR_SRC1_ALPHA diff -Nru dxvk-0.95+ds1/src/dxvk/dxvk_util.h dxvk-0.96+ds1/src/dxvk/dxvk_util.h --- dxvk-0.95+ds1/src/dxvk/dxvk_util.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/dxvk_util.h 2019-01-26 17:41:48.000000000 +0000 @@ -212,6 +212,9 @@ VkComponentSwizzle component, uint32_t identity); + bool isBlendConstantBlendFactor( + VkBlendFactor factor); + bool isDualSourceBlendFactor( VkBlendFactor factor); diff -Nru dxvk-0.95+ds1/src/dxvk/hud/dxvk_hud.cpp dxvk-0.96+ds1/src/dxvk/hud/dxvk_hud.cpp --- dxvk-0.95+ds1/src/dxvk/hud/dxvk_hud.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/dxvk/hud/dxvk_hud.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -16,14 +16,12 @@ m_hudFramerate (config.elements), m_hudStats (config.elements) { // Set up constant state - m_rsState.polygonMode = VK_POLYGON_MODE_FILL; - m_rsState.cullMode = VK_CULL_MODE_BACK_BIT; - m_rsState.frontFace = VK_FRONT_FACE_CLOCKWISE; - m_rsState.depthClampEnable = VK_FALSE; - m_rsState.depthBiasEnable = VK_FALSE; - m_rsState.depthBiasConstant = 0.0f; - m_rsState.depthBiasClamp = 0.0f; - m_rsState.depthBiasSlope = 0.0f; + m_rsState.polygonMode = VK_POLYGON_MODE_FILL; + m_rsState.cullMode = VK_CULL_MODE_BACK_BIT; + m_rsState.frontFace = VK_FRONT_FACE_CLOCKWISE; + m_rsState.depthClipEnable = VK_FALSE; + m_rsState.depthBiasEnable = VK_FALSE; + m_rsState.sampleCount = VK_SAMPLE_COUNT_1_BIT; m_blendMode.enableBlending = VK_TRUE; m_blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE; diff -Nru dxvk-0.95+ds1/src/util/config/config.cpp dxvk-0.96+ds1/src/util/config/config.cpp --- dxvk-0.95+ds1/src/util/config/config.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/util/config/config.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -11,7 +11,7 @@ namespace dxvk { const static std::unordered_map g_appDefaults = {{ - /* Assassin's Creed Syndicate - amdags issues */ + /* Assassin's Creed Syndicate: amdags issues */ { "ACS.exe", {{ { "dxgi.customVendorId", "10de" }, }} }, @@ -19,7 +19,8 @@ { "Dishonored2.exe", {{ { "d3d11.allowMapFlagNoWait", "True" } }} }, - /* Elite Dangerous */ + /* Elite Dangerous: Compiles weird shaders * + * when running on AMD hardware */ { "EliteDangerous64.exe", {{ { "dxgi.customVendorId", "10de" }, }} }, @@ -27,7 +28,8 @@ { "EthanCarter-Win64-Shipping.exe", {{ { "dxgi.customVendorId", "10de" }, }} }, - /* The Evil Within */ + /* The Evil Within: Submits command lists * + * multiple times */ { "EvilWithin.exe", {{ { "d3d11.dcSingleUseMode", "False" }, }} }, @@ -35,39 +37,26 @@ { "EvilWithinDemo.exe", {{ { "d3d11.dcSingleUseMode", "False" }, }} }, - /* F1 2015 */ - { "F1_2015.exe", {{ - { "d3d11.fakeStreamOutSupport", "True" }, - }} }, /* Far Cry 5 */ { "FarCry5.exe", {{ { "d3d11.allowMapFlagNoWait", "True" } }} }, - /* Final Fantasy XV */ - { "ffxv_s.exe", {{ - { "d3d11.fakeStreamOutSupport", "True" }, - }} }, - /* Frostpunk */ + /* Frostpunk: Renders one frame with D3D9 * + * after creating the DXGI swap chain */ { "Frostpunk.exe", {{ { "dxgi.deferSurfaceCreation", "True" }, }} }, - /* Mafia 3 */ - { "mafia3.exe", {{ - { "d3d11.fakeStreamOutSupport", "True" }, - }} }, - /* Overwatch */ - { "Overwatch.exe", {{ - { "d3d11.fakeStreamOutSupport", "True" }, - }} }, - /* Quantum Break */ + /* Quantum Break: Mever initializes shared * + * memory in one of its compute shaders */ { "QuantumBreak.exe", {{ { "d3d11.zeroInitWorkgroupMemory", "True" }, }} }, - /* Anno 2205 */ + /* Anno 2205: Random crashes with state cache */ { "anno2205.exe", {{ { "dxvk.enableStateCache", "False" }, }} }, - /* Fifa '19 */ + /* Fifa '19: Binds typed buffer SRV to shader * + * that expects raw/structured buffer SRV */ { "FIFA19.exe", {{ { "dxvk.useRawSsbo", "True" }, }} }, @@ -83,6 +72,10 @@ { "NFS16.exe", {{ { "dxgi.nvapiHack", "False" }, }} }, + /* Mass Effect Andromeda */ + { "MassEffectAndromeda.exe", {{ + { "dxgi.nvapiHack", "False" }, + }} }, }}; diff -Nru dxvk-0.95+ds1/src/util/util_env.cpp dxvk-0.96+ds1/src/util/util_env.cpp --- dxvk-0.95+ds1/src/util/util_env.cpp 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/util/util_env.cpp 2019-01-26 17:41:48.000000000 +0000 @@ -1,29 +1,16 @@ #include "util_env.h" #include +#include #include "./com/com_include.h" namespace dxvk::env { - std::string getEnvVar(const std::string& name) { - int nameLen = ::MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.length() + 1, nullptr, 0); - - std::vector wideName(nameLen); - - ::MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.length() + 1, wideName.data(), nameLen); - - DWORD len = ::GetEnvironmentVariableW(wideName.data(), nullptr, 0); - - std::vector result; - - while (len > result.size()) { - result.resize(len); - len = ::GetEnvironmentVariableW( - wideName.data(), result.data(), result.size()); - } - - result.resize(len); - return str::fromws(result.data()); + std::string getEnvVar(const char* name) { + char* result = std::getenv(name); + return (result) + ? result + : ""; } diff -Nru dxvk-0.95+ds1/src/util/util_env.h dxvk-0.96+ds1/src/util/util_env.h --- dxvk-0.95+ds1/src/util/util_env.h 2019-01-12 20:42:49.000000000 +0000 +++ dxvk-0.96+ds1/src/util/util_env.h 2019-01-26 17:41:48.000000000 +0000 @@ -13,7 +13,7 @@ * \param [in] name Name of the variable * \returns Value of the variable */ - std::string getEnvVar(const std::string& name); + std::string getEnvVar(const char* name); /** * \brief Gets the executable name