From 6033b1ee0564eaa8ea2676bd722030b9ecd08760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 18:29:58 +0100 Subject: [PATCH] D3D11: Some cleanup. Fix backface culling. Wipeout still looks weird... --- GPU/D3D11/D3D11Util.cpp | 7 +- GPU/D3D11/DrawEngineD3D11.cpp | 5 +- GPU/D3D11/DrawEngineD3D11.h | 12 +- GPU/D3D11/FramebufferManagerD3D11.cpp | 41 +--- GPU/D3D11/StateMappingD3D11.cpp | 225 +++++++++------------- GPU/D3D11/StateMappingD3D11.h | 57 ++++++ GPU/Directx9/PixelShaderGeneratorDX9.cpp | 19 +- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 8 +- GPU/GPU.vcxproj | 1 + GPU/GPU.vcxproj.filters | 1 + GPU/Vulkan/FramebufferVulkan.cpp | 6 +- ext/native/math/dataconv.h | 5 +- ext/native/thin3d/thin3d.h | 2 + ext/native/thin3d/thin3d_d3d11.cpp | 8 +- ext/native/thin3d/thin3d_d3d9.cpp | 2 + ext/native/thin3d/thin3d_gl.cpp | 1 + ext/native/thin3d/thin3d_vulkan.cpp | 4 +- 17 files changed, 205 insertions(+), 199 deletions(-) create mode 100644 GPU/D3D11/StateMappingD3D11.h diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index baff704f05..256f57616a 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -53,6 +53,8 @@ ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code void StockObjectsD3D11::Create(ID3D11Device *device) { D3D11_BLEND_DESC blend_desc{}; + blend_desc.RenderTarget[0].BlendEnable = false; + blend_desc.IndependentBlendEnable = false; for (int i = 0; i < 16; i++) { blend_desc.RenderTarget[0].RenderTargetWriteMask = i; device->CreateBlendState(&blend_desc, &blendStateDisabledWithColorMask[i]); @@ -65,13 +67,10 @@ void StockObjectsD3D11::Create(ID3D11Device *device) { depth_desc.StencilReadMask = 0xFF; depth_desc.StencilWriteMask = 0xFF; depth_desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - depth_desc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; depth_desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; - depth_desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; depth_desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; - depth_desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; depth_desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - depth_desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depth_desc.BackFace = depth_desc.FrontFace; device->CreateDepthStencilState(&depth_desc, &depthDisabledStencilWrite); D3D11_RASTERIZER_DESC raster_desc{}; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 247bf17b37..0c6d7e44eb 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -842,11 +842,11 @@ rotateVBO: dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(), maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result); - ApplyDrawStateLate(result.setStencil, result.stencilValue); - if (result.action == SW_DRAW_PRIMITIVES) { const int vertexSize = sizeof(transformed[0]); + ApplyDrawStateLate(result.setStencil, result.stencilValue); + D3D11VertexShader *vshader; D3D11FragmentShader *fshader; shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false); @@ -964,4 +964,5 @@ bool DrawEngineD3D11::IsCodePtrVertexDecoder(const u8 *ptr) const { void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const float * pos, const float * tex, const float * col, int size, bool hasColor, bool hasTexCoords) { + // HW tessellation not yet supported } diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 42effbee24..bbf9c2feba 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -28,6 +28,7 @@ #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" +#include "GPU/D3D11/StateMappingD3D11.h" #include "GPU/D3D11/D3D11Util.h" struct DecVtxFormat; @@ -232,9 +233,6 @@ private: UVScale uvScale[MAX_DEFERRED_DRAW_CALLS]; - bool fboTexNeedBind_; - bool fboTexBound_; - // D3D11 state object caches std::map blendCache_; std::map depthStencilCache_; @@ -243,6 +241,14 @@ private: // Keep the depth state between ApplyDrawState and ApplyDrawStateLate ID3D11DepthStencilState *depthStencilState_; + // State keys + D3D11StateKeys keys_{}; + D3D11DynamicState dynState_{}; + + // Initial work on shader blending + bool fboTexNeedBind_; + bool fboTexBound_; + // Hardware tessellation class TessellationDataTransferD3D11 : public TessellationDataTransfer { private: diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index b195f36245..096df190c8 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -414,46 +414,7 @@ void FramebufferManagerD3D11::BlitFramebufferDepth(VirtualFramebuffer *src, Virt // Doesn't work. Use a shader maybe? draw_->BindBackbufferAsRenderTarget(); draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, src->width, src->height, 1, Draw::FB_DEPTH_BIT); - /* - LPDIRECT3DTEXTURE9 srcTex = (LPDIRECT3DTEXTURE9)draw_->GetFramebufferAPITexture(src->fbo, Draw::FB_DEPTH_BIT, 0); - LPDIRECT3DTEXTURE9 dstTex = (LPDIRECT3DTEXTURE9)draw_->GetFramebufferAPITexture(dst->fbo, Draw::FB_DEPTH_BIT, 0); - - if (srcTex && dstTex) { - D3DSURFACE_DESC srcDesc; - srcTex->GetLevelDesc(0, &srcDesc); - D3DSURFACE_DESC dstDesc; - dstTex->GetLevelDesc(0, &dstDesc); - - D3DLOCKED_RECT srcLock; - D3DLOCKED_RECT dstLock; - HRESULT srcLockRes = srcTex->LockRect(0, &srcLock, nullptr, D3DLOCK_READONLY); - HRESULT dstLockRes = dstTex->LockRect(0, &dstLock, nullptr, 0); - if (SUCCEEDED(srcLockRes) && SUCCEEDED(dstLockRes)) { - u32 pitch = std::min(srcLock.Pitch, dstLock.Pitch); - u32 w = std::min(pitch / 4, std::min(srcDesc.Width, dstDesc.Width)); - u32 h = std::min(srcDesc.Height, dstDesc.Height); - const u8 *srcp = (const u8 *)srcLock.pBits; - u8 *dstp = (u8 *)dstLock.pBits; - - if (w == pitch / 4 && srcLock.Pitch == dstLock.Pitch) { - CopyPixelDepthOnly((u32 *)dstp, (const u32 *)srcp, w * h); - } else { - for (u32 y = 0; y < h; ++y) { - CopyPixelDepthOnly((u32 *)dstp, (const u32 *)srcp, w); - dstp += dstLock.Pitch; - srcp += srcLock.Pitch; - } - } - } - if (SUCCEEDED(srcLockRes)) { - srcTex->UnlockRect(0); - } - if (SUCCEEDED(dstLockRes)) { - dstTex->UnlockRect(0); - } - } RebindFramebuffer(); - */ } } @@ -838,7 +799,6 @@ void ConvertFromRGBA8888(u8 *dst, u8 *src, u32 dstStride, u32 srcStride, u32 wid } void FramebufferManagerD3D11::PackFramebufferD3D11_(VirtualFramebuffer *vfb, int x, int y, int w, int h) { - /* if (!vfb->fbo) { ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferD3D11_: vfb->fbo == 0"); draw_->BindBackbufferAsRenderTarget(); @@ -852,6 +812,7 @@ void FramebufferManagerD3D11::PackFramebufferD3D11_(VirtualFramebuffer *vfb, int // Right now that's always 8888. DEBUG_LOG(HLE, "Reading framebuffer to mem, fb_address = %08x", fb_address); + /* LPDIRECT3DSURFACE9 renderTarget = (LPDIRECT3DSURFACE9)draw_->GetFramebufferAPITexture(vfb->fbo, Draw::FB_COLOR_BIT | Draw::FB_SURFACE_BIT, 0); D3DSURFACE_DESC desc; renderTarget->GetDesc(&desc); diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 48a2638d2f..51824625c5 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -29,6 +29,7 @@ #include "GPU/Common/FramebufferCommon.h" #include "GPU/D3D11/DrawEngineD3D11.h" +#include "GPU/D3D11/StateMappingD3D11.h" #include "GPU/D3D11/FramebufferManagerD3D11.h" #include "GPU/D3D11/TextureCacheD3D11.h" @@ -99,7 +100,6 @@ static const D3D11_PRIMITIVE_TOPOLOGY primToD3D11[8] = { D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, }; -// These are actually the same exact values/order/etc. as the GE ones, but for clarity... /* static const D3D11_LOGIC_OP logicOps[] = { D3D11_LOGIC_OP_CLEAR, @@ -132,62 +132,9 @@ static void ResetShaderBlending() { class FramebufferManagerD3D11; class ShaderManagerD3D11; -// TODO: Do this more progressively. No need to compute the entire state if the entire state hasn't changed. -// In Vulkan, we simply collect all the state together into a "pipeline key" - we don't actually set any state here -// (the caller is responsible for setting the little dynamic state that is supported, dynState). - -struct D3D11BlendKey { - // Blend - unsigned int blendEnable : 1; - unsigned int srcColor : 5; // D3D11_BLEND - unsigned int destColor : 5; // D3D11_BLEND - unsigned int srcAlpha : 5; // D3D11_BLEND - unsigned int destAlpha : 5; // D3D11_BLEND - unsigned int blendOpColor : 3; // D3D11_BLEND_OP - unsigned int blendOpAlpha : 3; // D3D11_BLEND_OP - unsigned int logicOpEnable : 1; - unsigned int logicOp : 4; // D3D11_LOGIC_OP - unsigned int colorWriteMask : 4; -}; - -struct D3D11DepthStencilKey { - // Depth/Stencil - unsigned int depthTestEnable : 1; - unsigned int depthWriteEnable : 1; - unsigned int depthCompareOp : 4; // D3D11_COMPARISON (-1 and we could fit it in 3 bits) - unsigned int stencilTestEnable : 1; - unsigned int stencilCompareFunc : 4; // D3D11_COMPARISON - unsigned int stencilPassOp : 4; // D3D11_STENCIL_OP - unsigned int stencilFailOp : 4; // D3D11_STENCIL_OP - unsigned int stencilDepthFailOp : 4; // D3D11_STENCIL_OP - unsigned int stencilWriteMask : 8; // Unfortunately these are baked into the state on D3D11 - unsigned int stencilCompareMask : 8; -}; - -struct D3D11RasterKey { - unsigned int cullMode : 2; // D3D11_CULL_MODE -}; - -// In D3D11 we cache blend state objects etc, and we simply emit keys, which are then also used to create these objects. -struct D3D11StateKeys { - D3D11BlendKey blend; - D3D11DepthStencilKey depthStencil; - D3D11RasterKey raster; -}; - -struct D3D11DynamicState { - int topology; - bool useBlendColor; - uint32_t blendColor; - bool useStencil; - uint8_t stencilRef; - D3D11_VIEWPORT viewport; - D3D11_RECT scissor; -}; - void DrawEngineD3D11::ApplyDrawState(int prim) { - D3D11StateKeys key{}; - D3D11DynamicState dynState{}; + memset(&keys_, 0, sizeof(keys_)); + memset(&dynState_, 0, sizeof(dynState_)); // Unfortunately, this isn't implemented yet. gstate_c.allowShaderBlend = false; @@ -214,36 +161,36 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } if (blendState.enabled) { - key.blend.blendEnable = true; - key.blend.blendOpColor = d3d11BlendEqLookup[(size_t)blendState.eqColor]; - key.blend.blendOpAlpha = d3d11BlendEqLookup[(size_t)blendState.eqAlpha]; - key.blend.srcColor = d3d11BlendFactorLookup[(size_t)blendState.srcColor]; - key.blend.srcAlpha = d3d11BlendFactorLookup[(size_t)blendState.srcAlpha]; - key.blend.destColor = d3d11BlendFactorLookup[(size_t)blendState.dstColor]; - key.blend.destAlpha = d3d11BlendFactorLookup[(size_t)blendState.dstAlpha]; + keys_.blend.blendEnable = true; + keys_.blend.blendOpColor = d3d11BlendEqLookup[(size_t)blendState.eqColor]; + keys_.blend.blendOpAlpha = d3d11BlendEqLookup[(size_t)blendState.eqAlpha]; + keys_.blend.srcColor = d3d11BlendFactorLookup[(size_t)blendState.srcColor]; + keys_.blend.srcAlpha = d3d11BlendFactorLookup[(size_t)blendState.srcAlpha]; + keys_.blend.destColor = d3d11BlendFactorLookup[(size_t)blendState.dstColor]; + keys_.blend.destAlpha = d3d11BlendFactorLookup[(size_t)blendState.dstAlpha]; if (blendState.dirtyShaderBlend) { gstate_c.Dirty(DIRTY_SHADERBLEND); } - dynState.useBlendColor = blendState.useBlendColor; + dynState_.useBlendColor = blendState.useBlendColor; if (blendState.useBlendColor) { - dynState.blendColor = blendState.blendColor; + dynState_.blendColor = blendState.blendColor; } } else { - key.blend.blendEnable = false; - dynState.useBlendColor = false; + keys_.blend.blendEnable = false; + dynState_.useBlendColor = false; } - dynState.useStencil = false; + dynState_.useStencil = false; // Set ColorMask/Stencil/Depth if (gstate.isModeClear()) { - key.blend.logicOpEnable = false; - key.raster.cullMode = D3D11_CULL_NONE; + keys_.blend.logicOpEnable = false; + keys_.raster.cullMode = D3D11_CULL_NONE; - key.depthStencil.depthTestEnable = true; - key.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS; - key.depthStencil.depthWriteEnable = gstate.isClearModeDepthMask(); + keys_.depthStencil.depthTestEnable = true; + keys_.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS; + keys_.depthStencil.depthWriteEnable = gstate.isClearModeDepthMask(); if (gstate.isClearModeDepthMask()) { framebufferManager_->SetDepthUpdated(); } @@ -251,56 +198,56 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { // Color Test bool colorMask = gstate.isClearModeColorMask(); bool alphaMask = gstate.isClearModeAlphaMask(); - key.blend.colorWriteMask = (colorMask ? (1 | 2 | 4) : 0) | (alphaMask ? 8 : 0); + keys_.blend.colorWriteMask = (colorMask ? (1 | 2 | 4) : 0) | (alphaMask ? 8 : 0); // Stencil Test if (alphaMask) { - key.depthStencil.stencilTestEnable = true; - key.depthStencil.stencilCompareFunc = D3D11_COMPARISON_ALWAYS; - key.depthStencil.stencilPassOp = D3D11_STENCIL_OP_REPLACE; - key.depthStencil.stencilFailOp = D3D11_STENCIL_OP_REPLACE; - key.depthStencil.stencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; - dynState.useStencil = true; + keys_.depthStencil.stencilTestEnable = true; + keys_.depthStencil.stencilCompareFunc = D3D11_COMPARISON_ALWAYS; + keys_.depthStencil.stencilPassOp = D3D11_STENCIL_OP_REPLACE; + keys_.depthStencil.stencilFailOp = D3D11_STENCIL_OP_REPLACE; + keys_.depthStencil.stencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dynState_.useStencil = true; // In clear mode, the stencil value is set to the alpha value of the vertex. // A normal clear will be 2 points, the second point has the color. // We override this value in the pipeline from software transform for clear rectangles. - dynState.stencilRef = 0xFF; - key.depthStencil.stencilWriteMask = 0xFF; + dynState_.stencilRef = 0xFF; + keys_.depthStencil.stencilWriteMask = 0xFF; } else { - key.depthStencil.stencilTestEnable = false; - dynState.useStencil = false; + keys_.depthStencil.stencilTestEnable = false; + dynState_.useStencil = false; } } else { if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { // Logic Ops if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) { - key.blend.logicOpEnable = true; + keys_.blend.logicOpEnable = true; // key.blendKey.logicOp = logicOps[gstate.getLogicOp()]; } else { - key.blend.logicOpEnable = false; + keys_.blend.logicOpEnable = false; } } // Set cull bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); - key.raster.cullMode = wantCull ? (gstate.getCullMode() ? D3D11_CULL_FRONT : D3D11_CULL_BACK) : D3D11_CULL_NONE; + keys_.raster.cullMode = wantCull ? (gstate.getCullMode() ? D3D11_CULL_FRONT : D3D11_CULL_BACK) : D3D11_CULL_NONE; // Depth Test if (gstate.isDepthTestEnabled()) { - key.depthStencil.depthTestEnable = true; - key.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; - key.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled(); + keys_.depthStencil.depthTestEnable = true; + keys_.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; + keys_.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled(); if (gstate.isDepthWriteEnabled()) { framebufferManager_->SetDepthUpdated(); } } else { - key.depthStencil.depthTestEnable = false; - key.depthStencil.depthWriteEnable = false; - key.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS; + keys_.depthStencil.depthTestEnable = false; + keys_.depthStencil.depthWriteEnable = false; + keys_.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS; } // PSP color/alpha mask is per bit but we can only support per byte. @@ -335,30 +282,30 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } } - key.blend.colorWriteMask = (rmask ? 1 : 0) | (gmask ? 2 : 0) | (bmask ? 4 : 0) | (amask ? 8 : 0); + keys_.blend.colorWriteMask = (rmask ? 1 : 0) | (gmask ? 2 : 0) | (bmask ? 4 : 0) | (amask ? 8 : 0); GenericStencilFuncState stencilState; ConvertStencilFuncState(stencilState); // Stencil Test if (stencilState.enabled) { - key.depthStencil.stencilTestEnable = true; - key.depthStencil.stencilCompareFunc = compareOps[stencilState.testFunc]; - key.depthStencil.stencilPassOp = stencilOps[stencilState.zPass]; - key.depthStencil.stencilFailOp = stencilOps[stencilState.sFail]; - key.depthStencil.stencilDepthFailOp = stencilOps[stencilState.zFail]; - key.depthStencil.stencilCompareMask = stencilState.testMask; - key.depthStencil.stencilWriteMask = stencilState.writeMask; - dynState.useStencil = true; - dynState.stencilRef = stencilState.testRef; + keys_.depthStencil.stencilTestEnable = true; + keys_.depthStencil.stencilCompareFunc = compareOps[stencilState.testFunc]; + keys_.depthStencil.stencilPassOp = stencilOps[stencilState.zPass]; + keys_.depthStencil.stencilFailOp = stencilOps[stencilState.sFail]; + keys_.depthStencil.stencilDepthFailOp = stencilOps[stencilState.zFail]; + keys_.depthStencil.stencilCompareMask = stencilState.testMask; + keys_.depthStencil.stencilWriteMask = stencilState.writeMask; + dynState_.useStencil = true; + dynState_.stencilRef = stencilState.testRef; } else { - key.depthStencil.stencilTestEnable = false; - dynState.useStencil = false; + keys_.depthStencil.stencilTestEnable = false; + dynState_.useStencil = false; } } - dynState.topology = primToD3D11[prim]; + dynState_.topology = primToD3D11[prim]; ViewportAndScissor vpAndScissor; ConvertViewportAndScissor(useBufferedRendering, @@ -375,7 +322,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { gstate_c.Dirty(DIRTY_DEPTHRANGE); } - D3D11_VIEWPORT &vp = dynState.viewport; + D3D11_VIEWPORT &vp = dynState_.viewport; vp.TopLeftX = vpAndScissor.viewportX; vp.TopLeftY = vpAndScissor.viewportY; vp.Width = vpAndScissor.viewportW; @@ -387,7 +334,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } context_->RSSetViewports(1, &vp); - D3D11_RECT &scissor = dynState.scissor; + D3D11_RECT &scissor = dynState_.scissor; if (vpAndScissor.scissorEnable) { scissor.left = vpAndScissor.scissorX; scissor.top = vpAndScissor.scissorY; @@ -413,9 +360,9 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } uint32_t blendKey, depthKey, rasterKey; - memcpy(&blendKey, &key.blend, sizeof(uint32_t)); - memcpy(&depthKey, &key.depthStencil, sizeof(uint32_t)); - memcpy(&rasterKey, &key.raster, sizeof(uint32_t)); + memcpy(&blendKey, &keys_.blend, sizeof(uint32_t)); + memcpy(&depthKey, &keys_.depthStencil, sizeof(uint32_t)); + memcpy(&rasterKey, &keys_.raster, sizeof(uint32_t)); ID3D11BlendState *bs = nullptr; ID3D11DepthStencilState *ds = nullptr; @@ -425,33 +372,37 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { if (blendIter == blendCache_.end()) { D3D11_BLEND_DESC desc{}; D3D11_RENDER_TARGET_BLEND_DESC &rt = desc.RenderTarget[0]; - rt.BlendEnable = key.blend.blendEnable; - rt.BlendOp = (D3D11_BLEND_OP)key.blend.blendOpColor; - rt.BlendOpAlpha = (D3D11_BLEND_OP)key.blend.blendOpAlpha; - rt.SrcBlend = (D3D11_BLEND)key.blend.srcColor; - rt.DestBlend = (D3D11_BLEND)key.blend.destColor; - rt.SrcBlendAlpha = (D3D11_BLEND)key.blend.srcAlpha; - rt.DestBlendAlpha = (D3D11_BLEND)key.blend.destAlpha; - rt.RenderTargetWriteMask = key.blend.colorWriteMask; + rt.BlendEnable = keys_.blend.blendEnable; + rt.BlendOp = (D3D11_BLEND_OP)keys_.blend.blendOpColor; + rt.BlendOpAlpha = (D3D11_BLEND_OP)keys_.blend.blendOpAlpha; + rt.SrcBlend = (D3D11_BLEND)keys_.blend.srcColor; + rt.DestBlend = (D3D11_BLEND)keys_.blend.destColor; + rt.SrcBlendAlpha = (D3D11_BLEND)keys_.blend.srcAlpha; + rt.DestBlendAlpha = (D3D11_BLEND)keys_.blend.destAlpha; + rt.RenderTargetWriteMask = keys_.blend.colorWriteMask; device_->CreateBlendState(&desc, &bs); blendCache_.insert(std::pair(blendKey, bs)); } else { bs = blendIter->second; } + float blendColor[4]; + Uint8x4ToFloat4(blendColor, dynState_.blendColor); + context_->OMSetBlendState(bs, blendColor, 0xFFFFFFFF); + auto depthIter = depthStencilCache_.find(depthKey); if (depthIter == depthStencilCache_.end()) { D3D11_DEPTH_STENCIL_DESC desc{}; - desc.DepthEnable = key.depthStencil.depthTestEnable; - desc.DepthWriteMask = key.depthStencil.depthWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - desc.DepthFunc = (D3D11_COMPARISON_FUNC)key.depthStencil.depthCompareOp; - desc.StencilEnable = key.depthStencil.stencilTestEnable; - desc.StencilReadMask = key.depthStencil.stencilCompareMask; - desc.StencilWriteMask = key.depthStencil.stencilWriteMask; - desc.FrontFace.StencilFailOp = (D3D11_STENCIL_OP)key.depthStencil.stencilFailOp; - desc.FrontFace.StencilPassOp = (D3D11_STENCIL_OP)key.depthStencil.stencilPassOp; - desc.FrontFace.StencilDepthFailOp = (D3D11_STENCIL_OP)key.depthStencil.stencilDepthFailOp; - desc.FrontFace.StencilFunc = (D3D11_COMPARISON_FUNC)key.depthStencil.stencilCompareFunc; + desc.DepthEnable = keys_.depthStencil.depthTestEnable; + desc.DepthWriteMask = keys_.depthStencil.depthWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + desc.DepthFunc = (D3D11_COMPARISON_FUNC)keys_.depthStencil.depthCompareOp; + desc.StencilEnable = keys_.depthStencil.stencilTestEnable; + desc.StencilReadMask = keys_.depthStencil.stencilCompareMask; + desc.StencilWriteMask = keys_.depthStencil.stencilWriteMask; + desc.FrontFace.StencilFailOp = (D3D11_STENCIL_OP)keys_.depthStencil.stencilFailOp; + desc.FrontFace.StencilPassOp = (D3D11_STENCIL_OP)keys_.depthStencil.stencilPassOp; + desc.FrontFace.StencilDepthFailOp = (D3D11_STENCIL_OP)keys_.depthStencil.stencilDepthFailOp; + desc.FrontFace.StencilFunc = (D3D11_COMPARISON_FUNC)keys_.depthStencil.stencilCompareFunc; desc.BackFace = desc.FrontFace; device_->CreateDepthStencilState(&desc, &ds); depthStencilCache_.insert(std::pair(depthKey, ds)); @@ -460,9 +411,19 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } depthStencilState_ = ds; - float blendColor[4]; - Uint8x4ToFloat4(blendColor, dynState.blendColor); - context_->OMSetBlendState(bs, blendColor, 0xFFFFFFFF); + auto rasterIter = rasterCache_.find(rasterKey); + if (rasterIter == rasterCache_.end()) { + D3D11_RASTERIZER_DESC desc{}; + desc.CullMode = (D3D11_CULL_MODE)(keys_.raster.cullMode); + desc.FillMode = D3D11_FILL_SOLID; + desc.ScissorEnable = TRUE; + desc.FrontCounterClockwise = TRUE; + device_->CreateRasterizerState(&desc, &rs); + rasterCache_.insert(std::pair(rasterKey, rs)); + } else { + rs = rasterIter->second; + } + context_->RSSetState(rs); } void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef) { diff --git a/GPU/D3D11/StateMappingD3D11.h b/GPU/D3D11/StateMappingD3D11.h new file mode 100644 index 0000000000..00a141e718 --- /dev/null +++ b/GPU/D3D11/StateMappingD3D11.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +// TODO: Do this more progressively. No need to compute the entire state if the entire state hasn't changed. +// In Vulkan, we simply collect all the state together into a "pipeline key" - we don't actually set any state here +// (the caller is responsible for setting the little dynamic state that is supported, dynState). + +struct D3D11BlendKey { + // Blend + unsigned int blendEnable : 1; + unsigned int srcColor : 5; // D3D11_BLEND + unsigned int destColor : 5; // D3D11_BLEND + unsigned int srcAlpha : 5; // D3D11_BLEND + unsigned int destAlpha : 5; // D3D11_BLEND + unsigned int blendOpColor : 3; // D3D11_BLEND_OP + unsigned int blendOpAlpha : 3; // D3D11_BLEND_OP + unsigned int logicOpEnable : 1; + unsigned int logicOp : 4; // D3D11_LOGIC_OP + unsigned int colorWriteMask : 4; +}; + +struct D3D11DepthStencilKey { + // Depth/Stencil + unsigned int depthTestEnable : 1; + unsigned int depthWriteEnable : 1; + unsigned int depthCompareOp : 4; // D3D11_COMPARISON (-1 and we could fit it in 3 bits) + unsigned int stencilTestEnable : 1; + unsigned int stencilCompareFunc : 4; // D3D11_COMPARISON + unsigned int stencilPassOp : 4; // D3D11_STENCIL_OP + unsigned int stencilFailOp : 4; // D3D11_STENCIL_OP + unsigned int stencilDepthFailOp : 4; // D3D11_STENCIL_OP + unsigned int stencilWriteMask : 8; // Unfortunately these are baked into the state on D3D11 + unsigned int stencilCompareMask : 8; +}; + +struct D3D11RasterKey { + unsigned int cullMode : 2; // D3D11_CULL_MODE +}; + +// In D3D11 we cache blend state objects etc, and we simply emit keys, which are then also used to create these objects. +struct D3D11StateKeys { + D3D11BlendKey blend; + D3D11DepthStencilKey depthStencil; + D3D11RasterKey raster; +}; + +struct D3D11DynamicState { + int topology; + bool useBlendColor; + uint32_t blendColor; + bool useStencil; + uint8_t stencilRef; + D3D11_VIEWPORT viewport; + D3D11_RECT scissor; +}; diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/PixelShaderGeneratorDX9.cpp index 15a75b3464..a59bb1f519 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/PixelShaderGeneratorDX9.cpp @@ -111,10 +111,18 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage } if (enableAlphaTest) { - WRITE(p, "float roundAndScaleTo255f(float x) { return floor(x * 255.0f + 0.5f); }\n"); + if (lang == HLSL_D3D11) { + WRITE(p, "uint roundAndScaleTo255f(float x) { return uint(floor(x * 255.0f + 0.5f)); }\n"); + } else { + WRITE(p, "float roundAndScaleTo255f(float x) { return floor(x * 255.0f + 0.5f); }\n"); + } } if (enableColorTest) { - WRITE(p, "float3 roundAndScaleTo255v(float3 x) { return floor(x * 255.0f + 0.5f); }\n"); + if (lang == HLSL_D3D11) { + WRITE(p, "uint3 roundAndScaleTo255v(float3 x) { return uint3(floor(x * 255.0f + 0.5f)); }\n"); + } else { + WRITE(p, "float3 roundAndScaleTo255v(float3 x) { return floor(x * 255.0f + 0.5f); }\n"); + } } WRITE(p, "struct PS_IN {\n"); @@ -126,7 +134,7 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage WRITE(p, " float3 v_color1: COLOR1;\n"); } if (enableFog) { - WRITE(p, " float2 v_fogdepth: TEXCOORD1;\n"); + WRITE(p, " float v_fogdepth: TEXCOORD1;\n"); } WRITE(p, "};\n"); @@ -297,7 +305,8 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage const char * test = colorTestFuncs[colorTestFunc]; WRITE(p, " float3 colortest = roundAndScaleTo255v(v.rgb);\n"); WRITE(p, " if ((colortest.r %s u_alphacolorref.r) && (colortest.g %s u_alphacolorref.g) && (colortest.b %s u_alphacolorref.b )) clip(-1);\n", test, test, test); - } else { + } + else { WRITE(p, " clip(-1);\n"); } } @@ -311,7 +320,7 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage } if (enableFog) { - WRITE(p, " float fogCoef = clamp(In.v_fogdepth.x, 0.0, 1.0);\n"); + WRITE(p, " float fogCoef = clamp(In.v_fogdepth, 0.0, 1.0);\n"); WRITE(p, " v = lerp(float4(u_fogcolor, v.a), v, fogCoef);\n"); } diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 37b2c47645..c2e9cfbb09 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -230,7 +230,7 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l WRITE(p, " float3 v_color1 : COLOR1;\n"); if (enableFog) { - WRITE(p, " float2 v_fogdepth: TEXCOORD1;\n"); + WRITE(p, " float v_fogdepth: TEXCOORD1;\n"); } if (lang == HLSL_DX9) { WRITE(p, " float4 gl_Position : POSITION;\n"); @@ -274,7 +274,7 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l WRITE(p, " Out.v_color1 = float3(0.0);\n"); } if (enableFog) { - WRITE(p, " Out.v_fogdepth.x = In.position.w;\n"); + WRITE(p, " Out.v_fogdepth = In.position.w;\n"); } if (lang == HLSL_D3D11) { if (gstate.isModeThrough()) { @@ -606,9 +606,9 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l // Compute fogdepth if (enableFog) { if (lang == HLSL_D3D11) { - WRITE(p, " Out.v_fogdepth.x = (viewPos.z + u_fogcoef_stencilreplace.x) * u_fogcoef_stencilreplace.y;\n"); + WRITE(p, " Out.v_fogdepth = (viewPos.z + u_fogcoef_stencilreplace.x) * u_fogcoef_stencilreplace.y;\n"); } else { - WRITE(p, " Out.v_fogdepth.x = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n"); + WRITE(p, " Out.v_fogdepth = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n"); } } } diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 195417444c..12e66fe50b 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -210,6 +210,7 @@ + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index b646468b14..d3d36e2508 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -255,6 +255,7 @@ D3D11 + diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 71fe336a45..92d62e98a8 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -22,6 +22,7 @@ #include "base/timeutil.h" #include "math/lin/matrix4x4.h" +#include "math/dataconv.h" #include "ext/native/thin3d/thin3d.h" #include "Common/Vulkan/VulkanContext.h" @@ -256,10 +257,7 @@ void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, boo CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL); VkClearValue colorValue, depthValue; - colorValue.color.float32[0] = (color & 0xFF) * (1.0f / 255.0f); - colorValue.color.float32[1] = ((color >> 8) & 0xFF) * (1.0f / 255.0f); - colorValue.color.float32[2] = ((color >> 16) & 0xFF) * (1.0f / 255.0f); - colorValue.color.float32[3] = ((color >> 24) & 0xFF) * (1.0f / 255.0f); + Uint8x4ToFloat4(colorValue.color.float32, color); depthValue.depthStencil.depth = depth; depthValue.depthStencil.stencil = (color >> 24) & 0xFF; diff --git a/ext/native/math/dataconv.h b/ext/native/math/dataconv.h index 46ea8b84be..5edf0d0d04 100644 --- a/ext/native/math/dataconv.h +++ b/ext/native/math/dataconv.h @@ -3,8 +3,11 @@ #include #include -// Utilities useful for filling in std140-layout uniform buffers. +#ifdef _M_SSE +#include > +#endif +// Utilities useful for filling in std140-layout uniform buffers, and similar. // LSBs in f[0], etc. // Could be SSE optimized. diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index c88309eb9f..b5b9c3311f 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -536,6 +536,8 @@ struct DeviceCaps { bool tesselationShaderSupported; bool multiViewport; bool dualSourceBlend; + bool framebufferCopySupported; + bool framebufferBlitSupported; }; struct TextureDesc { diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 7eaf004e3b..a95f2e2ef9 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -186,6 +186,10 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *co dxgiDevice->Release(); } + caps_.dualSourceBlend = true; + caps_.depthRangeMinusOneToOne = false; + caps_.framebufferBlitSupported = false; + int width; int height; GetRes(hWnd_, width, height); @@ -1141,9 +1145,7 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x return; } - D3D11_BOX srcBox{ - x, y, z, x+width, y+height, z+depth - }; + D3D11_BOX srcBox{(UINT)x, (UINT)y, (UINT)z, (UINT)(x+width), (UINT)(y+height), (UINT)(z+depth)}; context_->CopySubresourceRegion(dstTex, dstLevel, dstX, dstY, dstZ, srcTex, level, &srcBox); } diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index 7b75b759a0..306497ec4e 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -595,6 +595,8 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.preferredDepthBufferFormat = DataFormat::D24_S8; caps_.dualSourceBlend = false; caps_.tesselationShaderSupported = false; + caps_.framebufferBlitSupported = true; + caps_.framebufferCopySupported = false; if (d3d) { D3DDISPLAYMODE displayMode; d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode); diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 30c2539f4a..75ad9259af 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -615,6 +615,7 @@ OpenGLContext::OpenGLContext() { } else { caps_.preferredDepthBufferFormat = DataFormat::D24_S8; } + caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object; } OpenGLContext::~OpenGLContext() { diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 16f34b814e..45d2ea3044 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -639,7 +639,9 @@ VKContext::VKContext(VulkanContext *vulkan) caps_.tesselationShaderSupported = vulkan->GetFeaturesAvailable().tessellationShader != 0; caps_.multiViewport = vulkan->GetFeaturesAvailable().multiViewport != 0; caps_.dualSourceBlend = vulkan->GetFeaturesAvailable().dualSrcBlend != 0; - + caps_.framebufferBlitSupported = true; + caps_.framebufferCopySupported = true; + caps_.preferredDepthBufferFormat = DataFormat::D24_S8; device_ = vulkan->GetDevice(); queue_ = vulkan->GetGraphicsQueue();