From 175b97ef3453af65921e9aa30680f02ed5e9642f Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 8 Feb 2017 17:35:41 +0100 Subject: [PATCH 01/40] Start stubbing out a new D3D11 backend --- GPU/Common/ShaderId.h | 10 +- GPU/Common/ShaderUniforms.cpp | 215 ++++++++++++ GPU/Common/ShaderUniforms.h | 147 ++++++++ GPU/D3D11/FragmentShaderGeneratorD3D11.cpp | 5 + GPU/D3D11/FragmentShaderGeneratorD3D11.h | 5 + GPU/D3D11/ShaderManagerD3D11.cpp | 273 +++++++++++++++ GPU/D3D11/ShaderManagerD3D11.h | 145 ++++++++ GPU/D3D11/StateMappingD3D11.cpp | 379 +++++++++++++++++++++ GPU/D3D11/VertexShaderGeneratorD3D11.cpp | 5 + GPU/D3D11/VertexShaderGeneratorD3D11.h | 5 + GPU/Directx9/PixelShaderGeneratorDX9.h | 2 - GPU/GPU.vcxproj | 19 +- GPU/GPU.vcxproj.filters | 32 +- GPU/Vulkan/ShaderManagerVulkan.cpp | 213 +----------- GPU/Vulkan/ShaderManagerVulkan.h | 103 +----- 15 files changed, 1234 insertions(+), 324 deletions(-) create mode 100644 GPU/Common/ShaderUniforms.cpp create mode 100644 GPU/Common/ShaderUniforms.h create mode 100644 GPU/D3D11/FragmentShaderGeneratorD3D11.cpp create mode 100644 GPU/D3D11/FragmentShaderGeneratorD3D11.h create mode 100644 GPU/D3D11/ShaderManagerD3D11.cpp create mode 100644 GPU/D3D11/ShaderManagerD3D11.h create mode 100644 GPU/D3D11/StateMappingD3D11.cpp create mode 100644 GPU/D3D11/VertexShaderGeneratorD3D11.cpp create mode 100644 GPU/D3D11/VertexShaderGeneratorD3D11.h diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 0d2f27713c..07060d80e6 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include "base/basictypes.h" // TODO: There will be additional bits, indicating that groups of these will be @@ -93,9 +95,9 @@ struct ShaderID { } } - u32 d[2]; + uint32_t d[2]; bool operator < (const ShaderID &other) const { - for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++) { + for (size_t i = 0; i < sizeof(d) / sizeof(uint32_t); i++) { if (d[i] < other.d[i]) return true; if (d[i] > other.d[i]) @@ -104,7 +106,7 @@ struct ShaderID { return false; } bool operator == (const ShaderID &other) const { - for (size_t i = 0; i < sizeof(d) / sizeof(u32); i++) { + for (size_t i = 0; i < sizeof(d) / sizeof(uint32_t); i++) { if (d[i] != other.d[i]) return false; } @@ -142,7 +144,7 @@ struct ShaderID { bool CanUseHardwareTransform(int prim); -void ComputeVertexShaderID(ShaderID *id, u32 vertexType, bool useHWTransform); +void ComputeVertexShaderID(ShaderID *id, uint32_t vertexType, bool useHWTransform); // Generates a compact string that describes the shader. Useful in a list to get an overview // of the current flora of shaders. std::string VertexShaderDesc(const ShaderID &id); diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp new file mode 100644 index 0000000000..4fc4fff050 --- /dev/null +++ b/GPU/Common/ShaderUniforms.cpp @@ -0,0 +1,215 @@ +#include "ShaderUniforms.h" +#include "math/dataconv.h" +#include "math/lin/matrix4x4.h" +#include "math/math_util.h" +#include "math/lin/vec3.h" +#include "GPU/GPUState.h" +#include "GPU/Math3D.h" +#include "Core/Reporting.h" + +static void ConvertProjMatrixToVulkan(Matrix4x4 &in, bool invertedX, bool invertedY) { + const Vec3 trans(0, 0, gstate_c.vpZOffset * 0.5f + 0.5f); + const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); + in.translateAndScale(trans, scale); +} + +void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms) { + if (dirtyUniforms & DIRTY_TEXENV) { + Uint8x3ToFloat4(ub->texEnvColor, gstate.texenvcolor); + } + if (dirtyUniforms & DIRTY_ALPHACOLORREF) { + Uint8x3ToInt4_Alpha(ub->alphaColorRef, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask()); + } + if (dirtyUniforms & DIRTY_ALPHACOLORMASK) { + Uint8x3ToInt4_Alpha(ub->colorTestMask, gstate.getColorTestMask(), gstate.getAlphaTestMask()); + } + if (dirtyUniforms & DIRTY_FOGCOLOR) { + Uint8x3ToFloat4(ub->fogColor, gstate.fogcolor); + } + if (dirtyUniforms & DIRTY_SHADERBLEND) { + Uint8x3ToFloat4(ub->blendFixA, gstate.getFixA()); + Uint8x3ToFloat4(ub->blendFixB, gstate.getFixB()); + } + if (dirtyUniforms & DIRTY_TEXCLAMP) { + const float invW = 1.0f / (float)gstate_c.curTextureWidth; + const float invH = 1.0f / (float)gstate_c.curTextureHeight; + const int w = gstate.getTextureWidth(0); + const int h = gstate.getTextureHeight(0); + const float widthFactor = (float)w * invW; + const float heightFactor = (float)h * invH; + + // First wrap xy, then half texel xy (for clamp.) + ub->texClamp[0] = widthFactor; + ub->texClamp[1] = heightFactor; + ub->texClamp[2] = invW * 0.5f; + ub->texClamp[3] = invH * 0.5f; + ub->texClampOffset[0] = gstate_c.curTextureXOffset * invW; + ub->texClampOffset[1] = gstate_c.curTextureYOffset * invH; + } + + if (dirtyUniforms & DIRTY_PROJMATRIX) { + Matrix4x4 flippedMatrix; + memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); + + const bool invertedY = gstate_c.vpHeight < 0; + if (invertedY) { + flippedMatrix[1] = -flippedMatrix[1]; + flippedMatrix[5] = -flippedMatrix[5]; + flippedMatrix[9] = -flippedMatrix[9]; + flippedMatrix[13] = -flippedMatrix[13]; + } + const bool invertedX = gstate_c.vpWidth < 0; + if (invertedX) { + flippedMatrix[0] = -flippedMatrix[0]; + flippedMatrix[4] = -flippedMatrix[4]; + flippedMatrix[8] = -flippedMatrix[8]; + flippedMatrix[12] = -flippedMatrix[12]; + } + ConvertProjMatrixToVulkan(flippedMatrix, invertedX, invertedY); + CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr()); + } + + if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { + Matrix4x4 proj_through; + proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1); + CopyMatrix4x4(ub->proj_through, proj_through.getReadPtr()); + } + + // Transform + if (dirtyUniforms & DIRTY_WORLDMATRIX) { + ConvertMatrix4x3To4x4(ub->world, gstate.worldMatrix); + } + if (dirtyUniforms & DIRTY_VIEWMATRIX) { + ConvertMatrix4x3To4x4(ub->view, gstate.viewMatrix); + } + if (dirtyUniforms & DIRTY_TEXMATRIX) { + ConvertMatrix4x3To4x4(ub->tex, gstate.tgenMatrix); + } + + // Combined two small uniforms + if (dirtyUniforms & (DIRTY_FOGCOEF | DIRTY_STENCILREPLACEVALUE)) { + float fogcoef_stencil[3] = { + getFloat24(gstate.fog1), + getFloat24(gstate.fog2), + (float)gstate.getStencilTestRef() + }; + if (my_isinf(fogcoef_stencil[1])) { + // not really sure what a sensible value might be. + fogcoef_stencil[1] = fogcoef_stencil[1] < 0.0f ? -10000.0f : 10000.0f; + } else if (my_isnan(fogcoef_stencil[1])) { + // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 + // Just put the fog far away at a large finite distance. + // Infinities and NaNs are rather unpredictable in shaders on many GPUs + // so it's best to just make it a sane calculation. + fogcoef_stencil[0] = 100000.0f; + fogcoef_stencil[1] = 1.0f; + } +#ifndef MOBILE_DEVICE + else if (my_isnanorinf(fogcoef_stencil[1]) || my_isnanorinf(fogcoef_stencil[0])) { + ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef_stencil[0], fogcoef_stencil[1]); + } +#endif + CopyFloat3(ub->fogCoef_stencil, fogcoef_stencil); + } + + // Note - this one is not in lighting but in transformCommon as it has uses beyond lighting + if (dirtyUniforms & DIRTY_MATAMBIENTALPHA) { + Uint8x3ToFloat4_AlphaUint8(ub->matAmbient, gstate.materialambient, gstate.getMaterialAmbientA()); + } + + // Texturing + if (dirtyUniforms & DIRTY_UVSCALEOFFSET) { + const float invW = 1.0f / (float)gstate_c.curTextureWidth; + const float invH = 1.0f / (float)gstate_c.curTextureHeight; + const int w = gstate.getTextureWidth(0); + const int h = gstate.getTextureHeight(0); + const float widthFactor = (float)w * invW; + const float heightFactor = (float)h * invH; + ub->uvScaleOffset[0] = widthFactor; + ub->uvScaleOffset[1] = heightFactor; + ub->uvScaleOffset[2] = 0.0f; + ub->uvScaleOffset[3] = 0.0f; + } + + if (dirtyUniforms & DIRTY_DEPTHRANGE) { + float viewZScale = gstate.getViewportZScale(); + float viewZCenter = gstate.getViewportZCenter(); + float viewZInvScale; + + // We had to scale and translate Z to account for our clamped Z range. + // Therefore, we also need to reverse this to round properly. + // + // Example: scale = 65535.0, center = 0.0 + // Resulting range = -65535 to 65535, clamped to [0, 65535] + // gstate_c.vpDepthScale = 2.0f + // gstate_c.vpZOffset = -1.0f + // + // The projection already accounts for those, so we need to reverse them. + // + // Additionally, D3D9 uses a range from [0, 1]. We double and move the center. + viewZScale *= (1.0f / gstate_c.vpDepthScale) * 2.0f; + viewZCenter -= 65535.0f * gstate_c.vpZOffset + 32768.5f; + + if (viewZScale != 0.0) { + viewZInvScale = 1.0f / viewZScale; + } else { + viewZInvScale = 0.0; + } + + ub->depthRange[0] = viewZScale; + ub->depthRange[1] = viewZCenter; + ub->depthRange[2] = viewZCenter; + ub->depthRange[3] = viewZInvScale; + } +} + +void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms) { + // Lighting + if (dirtyUniforms & DIRTY_AMBIENT) { + Uint8x3ToFloat4_AlphaUint8(ub->ambientColor, gstate.ambientcolor, gstate.getAmbientA()); + } + if (dirtyUniforms & DIRTY_MATDIFFUSE) { + Uint8x3ToFloat4(ub->materialDiffuse, gstate.materialdiffuse); + } + if (dirtyUniforms & DIRTY_MATEMISSIVE) { + Uint8x3ToFloat4(ub->materialEmissive, gstate.materialemissive); + } + if (dirtyUniforms & DIRTY_MATSPECULAR) { + Uint8x3ToFloat4_Alpha(ub->materialSpecular, gstate.materialspecular, getFloat24(gstate.materialspecularcoef)); + } + + for (int i = 0; i < 4; i++) { + if (dirtyUniforms & (DIRTY_LIGHT0 << i)) { + if (gstate.isDirectionalLight(i)) { + // Prenormalize + float x = getFloat24(gstate.lpos[i * 3 + 0]); + float y = getFloat24(gstate.lpos[i * 3 + 1]); + float z = getFloat24(gstate.lpos[i * 3 + 2]); + float len = sqrtf(x*x + y*y + z*z); + if (len == 0.0f) + len = 1.0f; + else + len = 1.0f / len; + float vec[3] = { x * len, y * len, z * len }; + CopyFloat3To4(ub->lpos[i], vec); + } else { + ExpandFloat24x3ToFloat4(ub->lpos[i], &gstate.lpos[i * 3]); + } + ExpandFloat24x3ToFloat4(ub->ldir[i], &gstate.ldir[i * 3]); + ExpandFloat24x3ToFloat4(ub->latt[i], &gstate.latt[i * 3]); + CopyFloat1To4(ub->lightAngle[i], getFloat24(gstate.lcutoff[i])); + CopyFloat1To4(ub->lightSpotCoef[i], getFloat24(gstate.lconv[i])); + Uint8x3ToFloat4(ub->lightAmbient[i], gstate.lcolor[i * 3]); + Uint8x3ToFloat4(ub->lightDiffuse[i], gstate.lcolor[i * 3 + 1]); + Uint8x3ToFloat4(ub->lightSpecular[i], gstate.lcolor[i * 3 + 2]); + } + } +} + +void BoneUpdateUniforms(UB_VS_Bones *ub, uint64_t dirtyUniforms) { + for (int i = 0; i < 8; i++) { + if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) { + ConvertMatrix4x3To4x4(ub->bones[i], gstate.boneMatrix + 12 * i); + } + } +} diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h new file mode 100644 index 0000000000..f58e795ba1 --- /dev/null +++ b/GPU/Common/ShaderUniforms.h @@ -0,0 +1,147 @@ +#pragma once + +#include + +#include "ShaderCommon.h" + +// Used by the "modern" backends that use uniform buffers. They can share this without issue. + +// Pretty much full. Will need more bits for more fine grained dirty tracking for lights. +enum : uint64_t { + DIRTY_BASE_UNIFORMS = + DIRTY_WORLDMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX | DIRTY_ALPHACOLORREF | + DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEF | DIRTY_TEXENV | DIRTY_STENCILREPLACEVALUE | + DIRTY_ALPHACOLORMASK | DIRTY_SHADERBLEND | DIRTY_UVSCALEOFFSET | DIRTY_TEXCLAMP | DIRTY_DEPTHRANGE | DIRTY_MATAMBIENTALPHA, + DIRTY_LIGHT_UNIFORMS = + DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3 | + DIRTY_MATDIFFUSE | DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE | DIRTY_AMBIENT, +}; + +// TODO: Split into two structs, one for software transform and one for hardware transform, to save space. +// 512 bytes. Probably can't get to 256 (nVidia's UBO alignment). +struct UB_VS_FS_Base { + float proj[16]; + float proj_through[16]; + float view[16]; + float world[16]; + float tex[16]; // not that common, may want to break out + float uvScaleOffset[4]; + float depthRange[4]; + float fogCoef_stencil[4]; + float matAmbient[4]; + // Fragment data + float fogColor[4]; + float texEnvColor[4]; + int alphaColorRef[4]; + int colorTestMask[4]; + float blendFixA[4]; + float blendFixB[4]; + float texClamp[4]; + float texClampOffset[4]; +}; + +static const char *ub_baseStr = +R"( mat4 proj_mtx; + mat4 proj_through_mtx; + mat4 view_mtx; + mat4 world_mtx; + mat4 tex_mtx; + vec4 uvscaleoffset; + vec4 depthRange; + vec3 fogcoef_stencilreplace; + vec4 matambientalpha; + vec3 fogcolor; + vec3 texenv; + ivec4 alphacolorref; + ivec4 alphacolormask; + vec3 blendFixA; + vec3 blendFixB; + vec4 texclamp; + vec2 texclampoff; +)"; + +static const char *cb_baseStr = +R"( matrix proj_mtx; + matrix proj_through_mtx; + matrix view_mtx; + matrix world_mtx; + matrix tex_mtx; + float4 uvscaleoffset; + float4 depthRange; + float3 fogcoef_stencilreplace; + float4 matambientalpha; + float3 fogcolor; + float3 texenv; + ifloat4 alphacolorref; + ifloat4 alphacolormask; + float3 blendFixA; + float3 blendFixB; + float4 texclamp; + float2 texclampoff; +)"; + +// 576 bytes. Can we get down to 512? +struct UB_VS_Lights { + float ambientColor[4]; + float materialDiffuse[4]; + float materialSpecular[4]; + float materialEmissive[4]; + float lpos[4][4]; + float ldir[4][4]; + float latt[4][4]; + float lightAngle[4][4]; // TODO: Merge with lightSpotCoef, use .xy + float lightSpotCoef[4][4]; + float lightAmbient[4][4]; + float lightDiffuse[4][4]; + float lightSpecular[4][4]; +}; + +static const char *ub_vs_lightsStr = +R"( vec4 globalAmbient; + vec3 matdiffuse; + vec4 matspecular; + vec3 matemissive; + vec3 pos[4]; + vec3 dir[4]; + vec3 att[4]; + float angle[4]; + float spotCoef[4]; + vec3 ambient[4]; + vec3 diffuse[4]; + vec3 specular[4]; +)"; + +static const char *cb_vs_lightsStr = +R"( float4 globalAmbient; + float3 matdiffuse; + float4 matspecular; + float3 matemissive; + float3 pos[4]; + float3 dir[4]; + float3 att[4]; + float angle[4]; + float spotCoef[4]; + float3 ambient[4]; + float3 diffuse[4]; + float3 specular[4]; +)"; + +// With some cleverness, we could get away with uploading just half this when only the four first +// bones are being used. This is 512b, 256b would be great. +// Could also move to 4x3 matrices - would let us fit 5 bones into 256b. +struct UB_VS_Bones { + float bones[8][16]; +}; + +static const char *ub_vs_bonesStr = +R"( mat4 m[8]; +)"; + +static const char *cb_vs_bonesStr = +R"( matrix m[8]; +)"; + +void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms); +void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms); +void BoneUpdateUniforms(UB_VS_Bones *ub, uint64_t dirtyUniforms); + diff --git a/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp b/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp new file mode 100644 index 0000000000..86eac7c3ea --- /dev/null +++ b/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp @@ -0,0 +1,5 @@ +#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" + +void GenerateFragmentShaderD3D11(const ShaderID &id, char *buffer) { + +} diff --git a/GPU/D3D11/FragmentShaderGeneratorD3D11.h b/GPU/D3D11/FragmentShaderGeneratorD3D11.h new file mode 100644 index 0000000000..7f4ce59f8b --- /dev/null +++ b/GPU/D3D11/FragmentShaderGeneratorD3D11.h @@ -0,0 +1,5 @@ +#pragma once + +#include "GPU/Common/ShaderId.h" + +void GenerateFragmentShaderD3D11(const ShaderID &id, char *buffer); diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp new file mode 100644 index 0000000000..aad5b924bf --- /dev/null +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -0,0 +1,273 @@ +// Copyright (c) 2015- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#ifdef _WIN32 +#define SHADERLOG +#endif + +#include +#include + +#include + +#include "base/logging.h" +#include "math/lin/matrix4x4.h" +#include "math/math_util.h" +#include "math/dataconv.h" +#include "util/text/utf8.h" +#include "thin3d/d3d11_loader.h" +#include "Common/Common.h" +#include "Core/Config.h" +#include "Core/Reporting.h" +#include "GPU/Math3D.h" +#include "GPU/GPUState.h" +#include "GPU/ge_constants.h" +#include "GPU/D3D11/ShaderManagerD3D11.h" +#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" +#include "GPU/D3D11/VertexShaderGeneratorD3D11.h" + +D3D11FragmentShader::D3D11FragmentShader(ID3D11Device *device, ShaderID id, const char *code, bool useHWTransform) + : device_(device), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(0) { + source_ = code; + + std::string errorMessage; + +#ifdef SHADERLOG + OutputDebugStringA(code); +#endif + + uint8_t *bytecode; + UINT bytecodeSize; + + HRESULT hr = device_->CreatePixelShader(bytecode, bytecodeSize, nullptr, &module_); + if (FAILED(hr)) { + failed_ = true; + return; + } +} + +D3D11FragmentShader::~D3D11FragmentShader() { + if (module_) + module_->Release(); +} + +std::string D3D11FragmentShader::GetShaderString(DebugShaderStringType type) const { + switch (type) { + case SHADER_STRING_SOURCE_CODE: + return source_; + case SHADER_STRING_SHORT_DESC: + return FragmentShaderDesc(id_); + default: + return "N/A"; + } +} + +D3D11VertexShader::D3D11VertexShader(ID3D11Device *device, ShaderID id, const char *code, int vertType, bool useHWTransform, bool usesLighting) + : device_(device), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(nullptr), usesLighting_(usesLighting) { + source_ = code; + std::string errorMessage; + std::vector spirv; +#ifdef SHADERLOG + OutputDebugStringA(code); +#endif + uint8_t *bytecode; + UINT bytecodeSize; + + HRESULT hr = device_->CreateVertexShader(bytecode, bytecodeSize, nullptr, &module_); + if (FAILED(hr)) { + failed_ = true; + return; + } +} + +D3D11VertexShader::~D3D11VertexShader() { + if (module_) + module_->Release(); +} + +std::string D3D11VertexShader::GetShaderString(DebugShaderStringType type) const { + switch (type) { + case SHADER_STRING_SOURCE_CODE: + return source_; + case SHADER_STRING_SHORT_DESC: + return VertexShaderDesc(id_); + default: + return "N/A"; + } +} + +ShaderManagerD3D11::ShaderManagerD3D11(ID3D11Device *device, ID3D11DeviceContext *context) + : device_(device), context_(context), lastVShader_(nullptr), lastFShader_(nullptr) { + codeBuffer_ = new char[16384]; + memset(&ub_base, 0, sizeof(ub_base)); + memset(&ub_lights, 0, sizeof(ub_lights)); + memset(&ub_bones, 0, sizeof(ub_bones)); + + ILOG("sizeof(ub_base): %d", (int)sizeof(ub_base)); + ILOG("sizeof(ub_lights): %d", (int)sizeof(ub_lights)); + ILOG("sizeof(ub_bones): %d", (int)sizeof(ub_bones)); +} + +ShaderManagerD3D11::~ShaderManagerD3D11() { + ClearShaders(); + delete[] codeBuffer_; +} + +void ShaderManagerD3D11::Clear() { + for (auto iter = fsCache_.begin(); iter != fsCache_.end(); ++iter) { + delete iter->second; + } + for (auto iter = vsCache_.begin(); iter != vsCache_.end(); ++iter) { + delete iter->second; + } + fsCache_.clear(); + vsCache_.clear(); + lastFSID_.clear(); + lastVSID_.clear(); +} + +void ShaderManagerD3D11::ClearShaders() { + Clear(); + DirtyShader(); + gstate_c.Dirty(DIRTY_ALL_UNIFORMS); +} + +void ShaderManagerD3D11::DirtyShader() { + // Forget the last shader ID + lastFSID_.clear(); + lastVSID_.clear(); + lastVShader_ = nullptr; + lastFShader_ = nullptr; +} + +void ShaderManagerD3D11::DirtyLastShader() { // disables vertex arrays + lastVShader_ = nullptr; + lastFShader_ = nullptr; +} + +uint64_t ShaderManagerD3D11::UpdateUniforms() { + uint64_t dirty = gstate_c.GetDirtyUniforms(); + if (dirty != 0) { + if (dirty & DIRTY_BASE_UNIFORMS) + BaseUpdateUniforms(&ub_base, dirty); + if (dirty & DIRTY_LIGHT_UNIFORMS) + LightUpdateUniforms(&ub_lights, dirty); + if (dirty & DIRTY_BONE_UNIFORMS) + BoneUpdateUniforms(&ub_bones, dirty); + } + gstate_c.CleanUniforms(); + return dirty; +} + +void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, bool useHWTransform) { + ShaderID VSID; + ShaderID FSID; + ComputeVertexShaderID(&VSID, vertType, useHWTransform); + ComputeFragmentShaderID(&FSID); + + // Just update uniforms if this is the same shader as last time. + if (lastVShader_ != nullptr && lastFShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) { + *vshader = lastVShader_; + *fshader = lastFShader_; + // Already all set, no need to look up in shader maps. + return; + } + + VSCache::iterator vsIter = vsCache_.find(VSID); + D3D11VertexShader *vs; + if (vsIter == vsCache_.end()) { + // Vertex shader not in cache. Let's compile it. + bool usesLighting; + GenerateVertexShaderD3D11(VSID, codeBuffer_, &usesLighting); + vs = new D3D11VertexShader(device_, VSID, codeBuffer_, vertType, useHWTransform, usesLighting); + vsCache_[VSID] = vs; + } else { + vs = vsIter->second; + } + lastVSID_ = VSID; + + FSCache::iterator fsIter = fsCache_.find(FSID); + D3D11FragmentShader *fs; + if (fsIter == fsCache_.end()) { + // Fragment shader not in cache. Let's compile it. + GenerateFragmentShaderD3D11(FSID, codeBuffer_); + fs = new D3D11FragmentShader(device_, FSID, codeBuffer_, useHWTransform); + fsCache_[FSID] = fs; + } else { + fs = fsIter->second; + } + + lastFSID_ = FSID; + + lastVShader_ = vs; + lastFShader_ = fs; + + *vshader = vs; + *fshader = fs; +} + +std::vector ShaderManagerD3D11::DebugGetShaderIDs(DebugShaderType type) { + std::string id; + std::vector ids; + switch (type) { + case SHADER_TYPE_VERTEX: + { + for (auto iter : vsCache_) { + iter.first.ToString(&id); + ids.push_back(id); + } + break; + } + case SHADER_TYPE_FRAGMENT: + { + for (auto iter : fsCache_) { + iter.first.ToString(&id); + ids.push_back(id); + } + break; + } + default: + break; + } + return ids; +} + +std::string ShaderManagerD3D11::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) { + ShaderID shaderId; + shaderId.FromString(id); + switch (type) { + case SHADER_TYPE_VERTEX: + { + auto iter = vsCache_.find(shaderId); + if (iter == vsCache_.end()) { + return ""; + } + return iter->second->GetShaderString(stringType); + } + + case SHADER_TYPE_FRAGMENT: + { + auto iter = fsCache_.find(shaderId); + if (iter == fsCache_.end()) { + return ""; + } + return iter->second->GetShaderString(stringType); + } + default: + return "N/A"; + } +} diff --git a/GPU/D3D11/ShaderManagerD3D11.h b/GPU/D3D11/ShaderManagerD3D11.h new file mode 100644 index 0000000000..52ebdc4547 --- /dev/null +++ b/GPU/D3D11/ShaderManagerD3D11.h @@ -0,0 +1,145 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include + +#include + +#include "base/basictypes.h" +#include "Globals.h" +#include "GPU/Common/ShaderCommon.h" +#include "GPU/Common/ShaderId.h" +// #include "GPU/DX9/VertexShaderGeneratorD3D11.h" +// #include "GPU/DX9/FragmentShaderGeneratorD3D11.h" +#include "math/lin/matrix4x4.h" +#include "GPU/Common/ShaderUniforms.h" + +class D3D11Context; +class D3D11PushBuffer; + +class D3D11FragmentShader { +public: + D3D11FragmentShader(ID3D11Device *device, ShaderID id, const char *code, bool useHWTransform); + ~D3D11FragmentShader(); + + const std::string &source() const { return source_; } + + bool Failed() const { return failed_; } + bool UseHWTransform() const { return useHWTransform_; } + + std::string GetShaderString(DebugShaderStringType type) const; + ID3D11PixelShader *GetShader() const { return module_; } + +protected: + ID3D11PixelShader *module_; + + ID3D11Device *device_; + std::string source_; + bool failed_; + bool useHWTransform_; + ShaderID id_; +}; + +class D3D11VertexShader { +public: + D3D11VertexShader(ID3D11Device *device, ShaderID id, const char *code, int vertType, bool useHWTransform, bool usesLighting); + ~D3D11VertexShader(); + + const std::string &source() const { return source_; } + + bool Failed() const { return failed_; } + bool UseHWTransform() const { return useHWTransform_; } + bool HasBones() const { + return id_.Bit(VS_BIT_ENABLE_BONES); + } + bool HasLights() const { + return usesLighting_; + } + + std::string GetShaderString(DebugShaderStringType type) const; + ID3D11VertexShader *GetModule() const { return module_; } + +protected: + ID3D11VertexShader *module_; + + ID3D11Device *device_; + std::string source_; + bool failed_; + bool useHWTransform_; + bool usesLighting_; + ShaderID id_; +}; + +class D3D11PushBuffer; + +class ShaderManagerD3D11 : public ShaderManagerCommon { +public: + ShaderManagerD3D11(ID3D11Device *device, ID3D11DeviceContext *context); + ~ShaderManagerD3D11(); + + void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, bool useHWTransform); + void ClearShaders(); + void DirtyShader(); + void DirtyLastShader(); + + int GetNumVertexShaders() const { return (int)vsCache_.size(); } + int GetNumFragmentShaders() const { return (int)fsCache_.size(); } + + std::vector DebugGetShaderIDs(DebugShaderType type); + std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType); + + uint64_t UpdateUniforms(); + + // TODO: Avoid copying these buffers if same as last draw, can still point to it assuming we're still in the same pushbuffer. + // Applies dirty changes and copies the buffer. + bool IsBaseDirty() { return true; } + bool IsLightDirty() { return true; } + bool IsBoneDirty() { return true; } + + /* + uint32_t PushBaseBuffer(D3D11PushBuffer *dest, VkBuffer *buf); + uint32_t PushLightBuffer(D3D11PushBuffer *dest, VkBuffer *buf); + uint32_t PushBoneBuffer(D3D11PushBuffer *dest, VkBuffer *buf); + */ + +private: + void Clear(); + + ID3D11Device *device_; + ID3D11DeviceContext *context_; + + typedef std::map FSCache; + FSCache fsCache_; + + typedef std::map VSCache; + VSCache vsCache_; + + char *codeBuffer_; + + // Uniform block scratchpad. These (the relevant ones) are copied to the current pushbuffer at draw time. + UB_VS_FS_Base ub_base; + UB_VS_Lights ub_lights; + UB_VS_Bones ub_bones; + + D3D11FragmentShader *lastFShader_; + D3D11VertexShader *lastVShader_; + + ShaderID lastFSID_; + ShaderID lastVSID_; +}; \ No newline at end of file diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp new file mode 100644 index 0000000000..94fad0f300 --- /dev/null +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -0,0 +1,379 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include + +#include "GPU/Math3D.h" +#include "GPU/GPUState.h" +#include "GPU/ge_constants.h" +#include "GPU/Common/GPUStateUtils.h" +#include "Core/System.h" +#include "Core/Config.h" +#include "Core/Reporting.h" + +#include "GPU/Common/FramebufferCommon.h" + +// These tables all fit into u8s. +static const D3D11_BLEND d3d11BlendFactorLookup[(size_t)BlendFactor::COUNT] = { + D3D11_BLEND_ZERO, + D3D11_BLEND_ONE, + D3D11_BLEND_SRC_COLOR, + D3D11_BLEND_INV_SRC_COLOR, + D3D11_BLEND_DEST_COLOR, + D3D11_BLEND_INV_DEST_COLOR, + D3D11_BLEND_SRC_ALPHA, + D3D11_BLEND_INV_SRC_ALPHA, + D3D11_BLEND_DEST_ALPHA, + D3D11_BLEND_INV_DEST_ALPHA, + D3D11_BLEND_BLEND_FACTOR, + D3D11_BLEND_INV_BLEND_FACTOR, + D3D11_BLEND_BLEND_FACTOR, + D3D11_BLEND_INV_BLEND_FACTOR, + D3D11_BLEND_SRC1_COLOR, + D3D11_BLEND_INV_SRC1_COLOR, + D3D11_BLEND_SRC1_ALPHA, + D3D11_BLEND_INV_SRC1_ALPHA, +}; + +static const D3D11_BLEND_OP d3d11BlendEqLookup[(size_t)BlendEq::COUNT] = { + D3D11_BLEND_OP_ADD, + D3D11_BLEND_OP_SUBTRACT, + D3D11_BLEND_OP_REV_SUBTRACT, + D3D11_BLEND_OP_MIN, + D3D11_BLEND_OP_MAX, +}; + +static const D3D11_CULL_MODE cullingMode[] = { + D3D11_CULL_BACK, + D3D11_CULL_FRONT, +}; + +static const D3D11_COMPARISON_FUNC compareOps[] = { + D3D11_COMPARISON_NEVER, + D3D11_COMPARISON_ALWAYS, + D3D11_COMPARISON_EQUAL, + D3D11_COMPARISON_NOT_EQUAL, + D3D11_COMPARISON_LESS, + D3D11_COMPARISON_LESS_EQUAL, + D3D11_COMPARISON_GREATER, + D3D11_COMPARISON_GREATER_EQUAL, +}; + +static const D3D11_STENCIL_OP stencilOps[] = { + D3D11_STENCIL_OP_KEEP, + D3D11_STENCIL_OP_ZERO, + D3D11_STENCIL_OP_REPLACE, + D3D11_STENCIL_OP_INVERT, + D3D11_STENCIL_OP_INCR_SAT, + D3D11_STENCIL_OP_DECR_SAT, + D3D11_STENCIL_OP_KEEP, // reserved + D3D11_STENCIL_OP_KEEP, // reserved +}; + +static const D3D11_PRIMITIVE_TOPOLOGY primToD3D11[8] = { + D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, + D3D11_PRIMITIVE_TOPOLOGY_LINELIST, + D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED, // D3D11 doesn't do triangle fans. + 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, + D3D11_LOGIC_OP_AND, + D3D11_LOGIC_OP_AND_REVERSE, + D3D11_LOGIC_OP_COPY, + D3D11_LOGIC_OP_AND_INVERTED, + D3D11_LOGIC_OP_NO_OP, + D3D11_LOGIC_OP_XOR, + D3D11_LOGIC_OP_OR, + D3D11_LOGIC_OP_NOR, + D3D11_LOGIC_OP_EQUIVALENT, + D3D11_LOGIC_OP_INVERT, + D3D11_LOGIC_OP_OR_REVERSE, + D3D11_LOGIC_OP_COPY_INVERTED, + D3D11_LOGIC_OP_OR_INVERTED, + D3D11_LOGIC_OP_NAND, + D3D11_LOGIC_OP_SET, +}; +*/ + +static bool ApplyShaderBlending() { + return false; +} + +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 : 3; // D3D11_COMPARISON + unsigned int stencilTestEnable : 1; + unsigned int stencilCompareOp : 3; // D3D11_COMPARISON + unsigned int stencilPassOp : 4; // D3D11_STENCIL_OP + unsigned int stencilFailOp : 4; // D3D11_STENCIL_OP + unsigned int stencilDepthFailOp : 4; // D3D11_STENCIL_OP +}; + +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; + uint8_t stencilWriteMask; + uint8_t stencilCompareMask; + D3D11_VIEWPORT viewport; + D3D11_RECT scissor; +}; + +void ConvertStateToKeys(FramebufferManagerCommon *fbManager, ShaderManagerD3D11 *shaderManager, int prim, D3D11StateKeys &key, D3D11DynamicState &dynState) { + memset(&key, 0, sizeof(key)); + memset(&dynState, 0, sizeof(dynState)); + // Unfortunately, this isn't implemented yet. + gstate_c.allowShaderBlend = false; + + // Set blend - unless we need to do it in the shader. + GenericBlendState blendState; + ConvertBlendState(blendState, gstate_c.allowShaderBlend); + + bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + + ViewportAndScissor vpAndScissor; + ConvertViewportAndScissor(useBufferedRendering, + fbManager->GetRenderWidth(), fbManager->GetRenderHeight(), + fbManager->GetTargetBufferWidth(), fbManager->GetTargetBufferHeight(), + vpAndScissor); + + if (blendState.applyShaderBlending) { + if (ApplyShaderBlending()) { + // We may still want to do something about stencil -> alpha. + ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState); + } else { + // Until next time, force it off. + ResetShaderBlending(); + gstate_c.allowShaderBlend = false; + } + } else if (blendState.resetShaderBlending) { + ResetShaderBlending(); + } + + 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]; + if (blendState.dirtyShaderBlend) { + gstate_c.Dirty(DIRTY_SHADERBLEND); + } + dynState.useBlendColor = blendState.useBlendColor; + if (blendState.useBlendColor) { + dynState.blendColor = blendState.blendColor; + } + } else { + key.blend.blendEnable = false; + dynState.useBlendColor = false; + } + + dynState.useStencil = false; + + // Set ColorMask/Stencil/Depth + if (gstate.isModeClear()) { + key.blend.logicOpEnable = false; + key.raster.cullMode = D3D11_CULL_NONE; + + key.depthStencil.depthTestEnable = true; + key.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS; + key.depthStencil.depthWriteEnable = gstate.isClearModeDepthMask(); + if (gstate.isClearModeDepthMask()) { + fbManager->SetDepthUpdated(); + } + + // Color Test + bool colorMask = gstate.isClearModeColorMask(); + bool alphaMask = gstate.isClearModeAlphaMask(); + key.blend.colorWriteMask = (colorMask ? (1 | 2 | 4) : 0) | (alphaMask ? 8 : 0); + + // Stencil Test + if (alphaMask) { + key.depthStencil.stencilTestEnable = true; + key.depthStencil.stencilCompareOp = 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; + // 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; + dynState.stencilWriteMask = 0xFF; + } else { + key.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; + // key.blendKey.logicOp = logicOps[gstate.getLogicOp()]; + } else { + key.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; + + // Depth Test + if (gstate.isDepthTestEnabled()) { + key.depthStencil.depthTestEnable = true; + key.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; + key.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled(); + if (gstate.isDepthWriteEnabled()) { + fbManager->SetDepthUpdated(); + } + } else { + key.depthStencil.depthTestEnable = false; + key.depthStencil.depthWriteEnable = false; + key.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS; + } + + // PSP color/alpha mask is per bit but we can only support per byte. + // But let's do that, at least. And let's try a threshold. + bool rmask = (gstate.pmskc & 0xFF) < 128; + bool gmask = ((gstate.pmskc >> 8) & 0xFF) < 128; + bool bmask = ((gstate.pmskc >> 16) & 0xFF) < 128; + bool amask = (gstate.pmska & 0xFF) < 128; + +#ifndef MOBILE_DEVICE + u8 abits = (gstate.pmska >> 0) & 0xFF; + u8 rbits = (gstate.pmskc >> 0) & 0xFF; + u8 gbits = (gstate.pmskc >> 8) & 0xFF; + u8 bbits = (gstate.pmskc >> 16) & 0xFF; + if ((rbits != 0 && rbits != 0xFF) || (gbits != 0 && gbits != 0xFF) || (bbits != 0 && bbits != 0xFF)) { + WARN_LOG_REPORT_ONCE(rgbmask, G3D, "Unsupported RGB mask: r=%02x g=%02x b=%02x", rbits, gbits, bbits); + } + if (abits != 0 && abits != 0xFF) { + // The stencil part of the mask is supported. + WARN_LOG_REPORT_ONCE(amask, G3D, "Unsupported alpha/stencil mask: %02x", abits); + } +#endif + + // Let's not write to alpha if stencil isn't enabled. + if (!gstate.isStencilTestEnabled()) { + amask = false; + } else { + // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel. + if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) { + amask = false; + } + } + + key.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.stencilCompareOp = compareOps[stencilState.testFunc]; + key.depthStencil.stencilPassOp = stencilOps[stencilState.zPass]; + key.depthStencil.stencilFailOp = stencilOps[stencilState.sFail]; + key.depthStencil.stencilDepthFailOp = stencilOps[stencilState.zFail]; + dynState.useStencil = true; + dynState.stencilRef = stencilState.testRef; + dynState.stencilCompareMask = stencilState.testMask; + dynState.stencilWriteMask = stencilState.writeMask; + } else { + key.depthStencil.stencilTestEnable = false; + dynState.useStencil = false; + } + } + + dynState.topology = primToD3D11[prim]; + + D3D11_VIEWPORT &vp = dynState.viewport; + vp.TopLeftX = vpAndScissor.viewportX; + vp.TopLeftY = vpAndScissor.viewportY; + vp.Width = vpAndScissor.viewportW; + vp.Height = vpAndScissor.viewportH; + vp.MinDepth = vpAndScissor.depthRangeMin; + vp.MaxDepth = vpAndScissor.depthRangeMax; + if (vpAndScissor.dirtyProj) { + gstate_c.Dirty(DIRTY_PROJMATRIX); + } + + D3D11_RECT &scissor = dynState.scissor; + scissor.left = vpAndScissor.scissorX; + scissor.top = vpAndScissor.scissorY; + scissor.right = vpAndScissor.scissorX + vpAndScissor.scissorW; + scissor.bottom = vpAndScissor.scissorY + vpAndScissor.scissorH; + + float depthMin = vpAndScissor.depthRangeMin; + float depthMax = vpAndScissor.depthRangeMax; + + if (depthMin < 0.0f) depthMin = 0.0f; + if (depthMax > 1.0f) depthMax = 1.0f; + if (vpAndScissor.dirtyDepth) { + gstate_c.Dirty(DIRTY_DEPTHRANGE); + } +} diff --git a/GPU/D3D11/VertexShaderGeneratorD3D11.cpp b/GPU/D3D11/VertexShaderGeneratorD3D11.cpp new file mode 100644 index 0000000000..22c90210d1 --- /dev/null +++ b/GPU/D3D11/VertexShaderGeneratorD3D11.cpp @@ -0,0 +1,5 @@ +#include "GPU/D3D11/VertexShaderGeneratorD3D11.h" + +void GenerateVertexShaderD3D11(const ShaderID &id, char *buffer, bool *usesLighting) { + +} diff --git a/GPU/D3D11/VertexShaderGeneratorD3D11.h b/GPU/D3D11/VertexShaderGeneratorD3D11.h new file mode 100644 index 0000000000..746f4a0ce1 --- /dev/null +++ b/GPU/D3D11/VertexShaderGeneratorD3D11.h @@ -0,0 +1,5 @@ +#pragma once + +#include "GPU/Common/ShaderId.h" + +void GenerateVertexShaderD3D11(const ShaderID &id, char *buffer, bool *usesLighting); diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.h b/GPU/Directx9/PixelShaderGeneratorDX9.h index 44914dfd2a..a2373dbc15 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.h +++ b/GPU/Directx9/PixelShaderGeneratorDX9.h @@ -17,8 +17,6 @@ #pragma once -#include "Globals.h" - #include "GPU/Common/ShaderId.h" namespace DX9 { diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 8e9d23ad04..2c509f8848 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -83,7 +83,7 @@ Level3 - ../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) StreamingSIMDExtensions2 Fast @@ -105,7 +105,7 @@ Level3 - ../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; NotSet Fast false @@ -131,7 +131,7 @@ MaxSpeed true true - ../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; false StreamingSIMDExtensions2 Fast @@ -157,7 +157,7 @@ MaxSpeed true true - ../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; + ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; false NotSet Fast @@ -190,6 +190,7 @@ + @@ -202,6 +203,9 @@ + + + @@ -261,6 +265,7 @@ + true @@ -286,6 +291,10 @@ + + + + @@ -344,4 +353,4 @@ - + \ No newline at end of file diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 58706bbffa..0c498c3f8a 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -25,6 +25,9 @@ {3c621896-140c-4c8b-8e4d-a478bfdeca8a} + + {88eb5cea-ec25-4881-89da-02f9f2fa8f3f} + @@ -222,6 +225,18 @@ GLES + + Common + + + D3D11 + + + D3D11 + + + D3D11 + @@ -428,5 +443,20 @@ GLES + + D3D11 + + + Common + + + D3D11 + + + D3D11 + + + D3D11 + - + \ No newline at end of file diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 18f7bf9192..b36f47d4c2 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -150,12 +150,6 @@ std::string VulkanVertexShader::GetShaderString(DebugShaderStringType type) cons } } -static void ConvertProjMatrixToVulkan(Matrix4x4 &in, bool invertedX, bool invertedY) { - const Vec3 trans(0, 0, gstate_c.vpZOffset * 0.5f + 0.5f); - const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); - in.translateAndScale(trans, scale); -} - ShaderManagerVulkan::ShaderManagerVulkan(VulkanContext *vulkan) : vulkan_(vulkan), lastVShader_(nullptr), lastFShader_(nullptr) { codeBuffer_ = new char[16384]; @@ -187,207 +181,6 @@ uint32_t ShaderManagerVulkan::PushBoneBuffer(VulkanPushBuffer *dest, VkBuffer *b return dest->PushAligned(&ub_bones, sizeof(ub_bones), uboAlignment_, buf); } -void ShaderManagerVulkan::BaseUpdateUniforms(uint64_t dirtyUniforms) { - if (dirtyUniforms & DIRTY_TEXENV) { - Uint8x3ToFloat4(ub_base.texEnvColor, gstate.texenvcolor); - } - if (dirtyUniforms & DIRTY_ALPHACOLORREF) { - Uint8x3ToInt4_Alpha(ub_base.alphaColorRef, gstate.getColorTestRef(), gstate.getAlphaTestRef() & gstate.getAlphaTestMask()); - } - if (dirtyUniforms & DIRTY_ALPHACOLORMASK) { - Uint8x3ToInt4_Alpha(ub_base.colorTestMask, gstate.getColorTestMask(), gstate.getAlphaTestMask()); - } - if (dirtyUniforms & DIRTY_FOGCOLOR) { - Uint8x3ToFloat4(ub_base.fogColor, gstate.fogcolor); - } - if (dirtyUniforms & DIRTY_SHADERBLEND) { - Uint8x3ToFloat4(ub_base.blendFixA, gstate.getFixA()); - Uint8x3ToFloat4(ub_base.blendFixB, gstate.getFixB()); - } - if (dirtyUniforms & DIRTY_TEXCLAMP) { - const float invW = 1.0f / (float)gstate_c.curTextureWidth; - const float invH = 1.0f / (float)gstate_c.curTextureHeight; - const int w = gstate.getTextureWidth(0); - const int h = gstate.getTextureHeight(0); - const float widthFactor = (float)w * invW; - const float heightFactor = (float)h * invH; - - // First wrap xy, then half texel xy (for clamp.) - ub_base.texClamp[0] = widthFactor; - ub_base.texClamp[1] = heightFactor; - ub_base.texClamp[2] = invW * 0.5f; - ub_base.texClamp[3] = invH * 0.5f; - ub_base.texClampOffset[0] = gstate_c.curTextureXOffset * invW; - ub_base.texClampOffset[1] = gstate_c.curTextureYOffset * invH; - } - - if (dirtyUniforms & DIRTY_PROJMATRIX) { - Matrix4x4 flippedMatrix; - memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); - - const bool invertedY = gstate_c.vpHeight < 0; - if (invertedY) { - flippedMatrix[1] = -flippedMatrix[1]; - flippedMatrix[5] = -flippedMatrix[5]; - flippedMatrix[9] = -flippedMatrix[9]; - flippedMatrix[13] = -flippedMatrix[13]; - } - const bool invertedX = gstate_c.vpWidth < 0; - if (invertedX) { - flippedMatrix[0] = -flippedMatrix[0]; - flippedMatrix[4] = -flippedMatrix[4]; - flippedMatrix[8] = -flippedMatrix[8]; - flippedMatrix[12] = -flippedMatrix[12]; - } - ConvertProjMatrixToVulkan(flippedMatrix, invertedX, invertedY); - CopyMatrix4x4(ub_base.proj, flippedMatrix.getReadPtr()); - } - - if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { - Matrix4x4 proj_through; - proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1); - CopyMatrix4x4(ub_base.proj_through, proj_through.getReadPtr()); - } - - // Transform - if (dirtyUniforms & DIRTY_WORLDMATRIX) { - ConvertMatrix4x3To4x4(ub_base.world, gstate.worldMatrix); - } - if (dirtyUniforms & DIRTY_VIEWMATRIX) { - ConvertMatrix4x3To4x4(ub_base.view, gstate.viewMatrix); - } - if (dirtyUniforms & DIRTY_TEXMATRIX) { - ConvertMatrix4x3To4x4(ub_base.tex, gstate.tgenMatrix); - } - - // Combined two small uniforms - if (dirtyUniforms & (DIRTY_FOGCOEF | DIRTY_STENCILREPLACEVALUE)) { - float fogcoef_stencil[3] = { - getFloat24(gstate.fog1), - getFloat24(gstate.fog2), - (float)gstate.getStencilTestRef() - }; - if (my_isinf(fogcoef_stencil[1])) { - // not really sure what a sensible value might be. - fogcoef_stencil[1] = fogcoef_stencil[1] < 0.0f ? -10000.0f : 10000.0f; - } else if (my_isnan(fogcoef_stencil[1])) { - // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 - // Just put the fog far away at a large finite distance. - // Infinities and NaNs are rather unpredictable in shaders on many GPUs - // so it's best to just make it a sane calculation. - fogcoef_stencil[0] = 100000.0f; - fogcoef_stencil[1] = 1.0f; - } -#ifndef MOBILE_DEVICE - else if (my_isnanorinf(fogcoef_stencil[1]) || my_isnanorinf(fogcoef_stencil[0])) { - ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef_stencil[0], fogcoef_stencil[1]); - } -#endif - CopyFloat3(ub_base.fogCoef_stencil, fogcoef_stencil); - } - - // Note - this one is not in lighting but in transformCommon as it has uses beyond lighting - if (dirtyUniforms & DIRTY_MATAMBIENTALPHA) { - Uint8x3ToFloat4_AlphaUint8(ub_base.matAmbient, gstate.materialambient, gstate.getMaterialAmbientA()); - } - - // Texturing - if (dirtyUniforms & DIRTY_UVSCALEOFFSET) { - const float invW = 1.0f / (float)gstate_c.curTextureWidth; - const float invH = 1.0f / (float)gstate_c.curTextureHeight; - const int w = gstate.getTextureWidth(0); - const int h = gstate.getTextureHeight(0); - const float widthFactor = (float)w * invW; - const float heightFactor = (float)h * invH; - ub_base.uvScaleOffset[0] = widthFactor; - ub_base.uvScaleOffset[1] = heightFactor; - ub_base.uvScaleOffset[2] = 0.0f; - ub_base.uvScaleOffset[3] = 0.0f; - } - - if (dirtyUniforms & DIRTY_DEPTHRANGE) { - float viewZScale = gstate.getViewportZScale(); - float viewZCenter = gstate.getViewportZCenter(); - float viewZInvScale; - - // We had to scale and translate Z to account for our clamped Z range. - // Therefore, we also need to reverse this to round properly. - // - // Example: scale = 65535.0, center = 0.0 - // Resulting range = -65535 to 65535, clamped to [0, 65535] - // gstate_c.vpDepthScale = 2.0f - // gstate_c.vpZOffset = -1.0f - // - // The projection already accounts for those, so we need to reverse them. - // - // Additionally, D3D9 uses a range from [0, 1]. We double and move the center. - viewZScale *= (1.0f / gstate_c.vpDepthScale) * 2.0f; - viewZCenter -= 65535.0f * gstate_c.vpZOffset + 32768.5f; - - if (viewZScale != 0.0) { - viewZInvScale = 1.0f / viewZScale; - } else { - viewZInvScale = 0.0; - } - - ub_base.depthRange[0] = viewZScale; - ub_base.depthRange[1] = viewZCenter; - ub_base.depthRange[2] = viewZCenter; - ub_base.depthRange[3] = viewZInvScale; - } -} - -void ShaderManagerVulkan::LightUpdateUniforms(uint64_t dirtyUniforms) { - // Lighting - if (dirtyUniforms & DIRTY_AMBIENT) { - Uint8x3ToFloat4_AlphaUint8(ub_lights.ambientColor, gstate.ambientcolor, gstate.getAmbientA()); - } - if (dirtyUniforms & DIRTY_MATDIFFUSE) { - Uint8x3ToFloat4(ub_lights.materialDiffuse, gstate.materialdiffuse); - } - if (dirtyUniforms & DIRTY_MATEMISSIVE) { - Uint8x3ToFloat4(ub_lights.materialEmissive, gstate.materialemissive); - } - if (dirtyUniforms & DIRTY_MATSPECULAR) { - Uint8x3ToFloat4_Alpha(ub_lights.materialSpecular, gstate.materialspecular, getFloat24(gstate.materialspecularcoef)); - } - - for (int i = 0; i < 4; i++) { - if (dirtyUniforms & (DIRTY_LIGHT0 << i)) { - if (gstate.isDirectionalLight(i)) { - // Prenormalize - float x = getFloat24(gstate.lpos[i * 3 + 0]); - float y = getFloat24(gstate.lpos[i * 3 + 1]); - float z = getFloat24(gstate.lpos[i * 3 + 2]); - float len = sqrtf(x*x + y*y + z*z); - if (len == 0.0f) - len = 1.0f; - else - len = 1.0f / len; - float vec[3] = { x * len, y * len, z * len }; - CopyFloat3To4(ub_lights.lpos[i], vec); - } else { - ExpandFloat24x3ToFloat4(ub_lights.lpos[i], &gstate.lpos[i * 3]); - } - ExpandFloat24x3ToFloat4(ub_lights.ldir[i], &gstate.ldir[i * 3]); - ExpandFloat24x3ToFloat4(ub_lights.latt[i], &gstate.latt[i * 3]); - CopyFloat1To4(ub_lights.lightAngle[i], getFloat24(gstate.lcutoff[i])); - CopyFloat1To4(ub_lights.lightSpotCoef[i], getFloat24(gstate.lconv[i])); - Uint8x3ToFloat4(ub_lights.lightAmbient[i], gstate.lcolor[i * 3]); - Uint8x3ToFloat4(ub_lights.lightDiffuse[i], gstate.lcolor[i * 3 + 1]); - Uint8x3ToFloat4(ub_lights.lightSpecular[i], gstate.lcolor[i * 3 + 2]); - } - } -} - -void ShaderManagerVulkan::BoneUpdateUniforms(uint64_t dirtyUniforms) { - for (int i = 0; i < 8; i++) { - if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) { - ConvertMatrix4x3To4x4(ub_bones.bones[i], gstate.boneMatrix + 12 * i); - } - } -} - void ShaderManagerVulkan::DeviceRestore(VulkanContext *vulkan) { vulkan_ = vulkan; uboAlignment_ = vulkan_->GetPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment; @@ -429,11 +222,11 @@ uint64_t ShaderManagerVulkan::UpdateUniforms() { uint64_t dirty = gstate_c.GetDirtyUniforms(); if (dirty != 0) { if (dirty & DIRTY_BASE_UNIFORMS) - BaseUpdateUniforms(dirty); + BaseUpdateUniforms(&ub_base, dirty); if (dirty & DIRTY_LIGHT_UNIFORMS) - LightUpdateUniforms(dirty); + LightUpdateUniforms(&ub_lights, dirty); if (dirty & DIRTY_BONE_UNIFORMS) - BoneUpdateUniforms(dirty); + BoneUpdateUniforms(&ub_bones, dirty); } gstate_c.CleanUniforms(); return dirty; diff --git a/GPU/Vulkan/ShaderManagerVulkan.h b/GPU/Vulkan/ShaderManagerVulkan.h index aa185a0479..2c8d6f646e 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.h +++ b/GPU/Vulkan/ShaderManagerVulkan.h @@ -27,104 +27,7 @@ #include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h" #include "GPU/Vulkan/VulkanUtil.h" #include "math/lin/matrix4x4.h" - -void ConvertProjMatrixToVulkan(Matrix4x4 & in); - -// Pretty much full. Will need more bits for more fine grained dirty tracking for lights. -enum : uint64_t { - DIRTY_BASE_UNIFORMS = - DIRTY_WORLDMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX | DIRTY_ALPHACOLORREF | - DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEF | DIRTY_TEXENV | DIRTY_STENCILREPLACEVALUE | - DIRTY_ALPHACOLORMASK | DIRTY_SHADERBLEND | DIRTY_UVSCALEOFFSET | DIRTY_TEXCLAMP | DIRTY_DEPTHRANGE | DIRTY_MATAMBIENTALPHA, - DIRTY_LIGHT_UNIFORMS = - DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3 | - DIRTY_MATDIFFUSE | DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE | DIRTY_AMBIENT, -}; - -// TODO: Split into two structs, one for software transform and one for hardware transform, to save space. -// 512 bytes. Probably can't get to 256 (nVidia's UBO alignment). -struct UB_VS_FS_Base { - float proj[16]; - float proj_through[16]; - float view[16]; - float world[16]; - float tex[16]; // not that common, may want to break out - float uvScaleOffset[4]; - float depthRange[4]; - float fogCoef_stencil[4]; - float matAmbient[4]; - // Fragment data - float fogColor[4]; - float texEnvColor[4]; - int alphaColorRef[4]; - int colorTestMask[4]; - float blendFixA[4]; - float blendFixB[4]; - float texClamp[4]; - float texClampOffset[4]; -}; - -static const char *ub_baseStr = -R"( mat4 proj_mtx; - mat4 proj_through_mtx; - mat4 view_mtx; - mat4 world_mtx; - mat4 tex_mtx; - vec4 uvscaleoffset; - vec4 depthRange; - vec3 fogcoef_stencilreplace; - vec4 matambientalpha; - vec3 fogcolor; - vec3 texenv; - ivec4 alphacolorref; - ivec4 alphacolormask; - vec3 blendFixA; - vec3 blendFixB; - vec4 texclamp; - vec2 texclampoff; -)"; - -// 576 bytes. Can we get down to 512? -struct UB_VS_Lights { - float ambientColor[4]; - float materialDiffuse[4]; - float materialSpecular[4]; - float materialEmissive[4]; - float lpos[4][4]; - float ldir[4][4]; - float latt[4][4]; - float lightAngle[4][4]; // TODO: Merge with lightSpotCoef, use .xy - float lightSpotCoef[4][4]; - float lightAmbient[4][4]; - float lightDiffuse[4][4]; - float lightSpecular[4][4]; -}; - -static const char *ub_vs_lightsStr = -R"( vec4 globalAmbient; - vec3 matdiffuse; - vec4 matspecular; - vec3 matemissive; - vec3 pos[4]; - vec3 dir[4]; - vec3 att[4]; - float angle[4]; - float spotCoef[4]; - vec3 ambient[4]; - vec3 diffuse[4]; - vec3 specular[4]; -)"; - -// With some cleverness, we could get away with uploading just half this when only the four first -// bones are being used. This is 512b, 256b would be great. -// Could also move to 4x3 matrices - would let us fit 5 bones into 256b. -struct UB_VS_Bones { - float bones[8][16]; -}; - -static const char *ub_vs_bonesStr = -R"( mat4 m[8]; -)"; +#include "GPU/Common/ShaderUniforms.h" class VulkanContext; class VulkanPushBuffer; @@ -215,10 +118,6 @@ public: uint32_t PushBoneBuffer(VulkanPushBuffer *dest, VkBuffer *buf); private: - void BaseUpdateUniforms(uint64_t dirtyUniforms); - void LightUpdateUniforms(uint64_t dirtyUniforms); - void BoneUpdateUniforms(uint64_t dirtyUniforms); - void Clear(); VulkanContext *vulkan_; From 02e7d371bd5aa9510b41c49443812640a725c653 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 8 Feb 2017 17:35:53 +0100 Subject: [PATCH 02/40] Enable selecting D3D11 on Windows --- UI/GameSettingsScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index b8aa467d82..2a202b0914 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -160,7 +160,7 @@ void GameSettingsScreen::CreateViews() { renderingBackendChoice->HideChoice(1); // D3D9 renderingBackendChoice->HideChoice(2); // D3D11 #else - renderingBackendChoice->HideChoice(2); // D3D11 + // renderingBackendChoice->HideChoice(2); // D3D11 #endif #if !defined(_WIN32) // TODO: Add dynamic runtime check for Vulkan support on Android From 01e11c64373f20973e7e004d06d3b87f11f78c8b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 8 Feb 2017 17:47:07 +0100 Subject: [PATCH 03/40] Some mostly empty files for D3D11 --- CMakeLists.txt | 24 ++++- GPU/D3D11/DepalettizeShaderD3D11.cpp | 0 GPU/D3D11/DepalettizeShaderD3D11.h | 20 ++++ GPU/D3D11/DrawEngineD3D11.cpp | 0 GPU/D3D11/DrawEngineD3D11.h | 23 ++++ GPU/D3D11/FragmentShaderGeneratorD3D11.h | 17 +++ GPU/D3D11/FramebufferManagerD3D11.cpp | 0 GPU/D3D11/FramebufferManagerD3D11.h | 20 ++++ GPU/D3D11/GPU_D3D11.cpp | 18 ++++ GPU/D3D11/GPU_D3D11.h | 132 +++++++++++++++++++++++ GPU/D3D11/TextureCacheD3D11.cpp | 0 GPU/D3D11/TextureCacheD3D11.h | 20 ++++ GPU/D3D11/VertexShaderGeneratorD3D11.h | 17 +++ GPU/GPU.cpp | 13 ++- GPU/GPU.vcxproj | 10 ++ GPU/GPU.vcxproj.filters | 33 +++++- 16 files changed, 341 insertions(+), 6 deletions(-) create mode 100644 GPU/D3D11/DepalettizeShaderD3D11.cpp create mode 100644 GPU/D3D11/DepalettizeShaderD3D11.h create mode 100644 GPU/D3D11/DrawEngineD3D11.cpp create mode 100644 GPU/D3D11/DrawEngineD3D11.h create mode 100644 GPU/D3D11/FramebufferManagerD3D11.cpp create mode 100644 GPU/D3D11/FramebufferManagerD3D11.h create mode 100644 GPU/D3D11/GPU_D3D11.cpp create mode 100644 GPU/D3D11/GPU_D3D11.h create mode 100644 GPU/D3D11/TextureCacheD3D11.cpp create mode 100644 GPU/D3D11/TextureCacheD3D11.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b3249f2eea..f2143496ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1156,13 +1156,35 @@ set(GPU_D3D9 GPU/Directx9/VertexShaderGeneratorDX9.h ) +set(GPU_D3D11 + GPU/D3D11/DepalettizeShaderD3D11.cpp + GPU/D3D11/DepalettizeShaderD3D11.h + GPU/D3D11/DrawEngineD3D11.cpp + GPU/D3D11/DrawEngineD3D11.h + GPU/D3D11/FragmentShaderGeneratorD3D11.cpp + GPU/D3D11/FragmentShaderGeneratorD3D11.h + GPU/D3D11/FramebufferManagerD3D11.cpp + GPU/D3D11/FramebufferManagerD3D11.h + GPU/D3D11/GPU_D3D11.cpp + GPU/D3D11/GPU_D3D11.h + GPU/D3D11/ShaderManagerD3D11.cpp + GPU/D3D11/ShaderManagerD3D11.h + GPU/D3D11/StateMappingD3D11.cpp + GPU/D3D11/StateMappingD3D11.h + GPU/D3D11/TextureCacheD3D11.cpp + GPU/D3D11/TextureCacheD3D11.h + GPU/D3D11/TextureScalerD3D11.cpp + GPU/D3D11/TextureScalerD3D11.h + GPU/D3D11/VertexShaderGeneratorD3D11.cpp + GPU/D3D11/VertexShaderGeneratorD3D11.h +) set(GPU_IMPLS ${GPU_GLES}) if(VULKAN) set(GPU_IMPLS ${GPU_IMPLS} ${GPU_VULKAN}) endif() if(WIN32) - list(APPEND GPU_IMPLS ${GPU_D3D9}) + list(APPEND GPU_IMPLS ${GPU_D3D9} ${GPU_D3D11}) endif() if(ARMV7 OR ARM64) diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/GPU/D3D11/DepalettizeShaderD3D11.h b/GPU/D3D11/DepalettizeShaderD3D11.h new file mode 100644 index 0000000000..73d7e85b00 --- /dev/null +++ b/GPU/D3D11/DepalettizeShaderD3D11.h @@ -0,0 +1,20 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +class DepalShaderCacheD3D11 {}; \ No newline at end of file diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h new file mode 100644 index 0000000000..a0222a9a33 --- /dev/null +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -0,0 +1,23 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +class DrawEngineD3D11 { +public: + void Flush() {} +}; \ No newline at end of file diff --git a/GPU/D3D11/FragmentShaderGeneratorD3D11.h b/GPU/D3D11/FragmentShaderGeneratorD3D11.h index 7f4ce59f8b..c7d49c0c9d 100644 --- a/GPU/D3D11/FragmentShaderGeneratorD3D11.h +++ b/GPU/D3D11/FragmentShaderGeneratorD3D11.h @@ -1,3 +1,20 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + #pragma once #include "GPU/Common/ShaderId.h" diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h new file mode 100644 index 0000000000..9676b47d8b --- /dev/null +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -0,0 +1,20 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +class FramebufferManagerD3D11 {}; \ No newline at end of file diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp new file mode 100644 index 0000000000..ebf88fedd6 --- /dev/null +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -0,0 +1,18 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "GPU/D3D11/GPU_D3D11.h" \ No newline at end of file diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h new file mode 100644 index 0000000000..79ec63a29e --- /dev/null +++ b/GPU/D3D11/GPU_D3D11.h @@ -0,0 +1,132 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include +#include +#include + +#include "GPU/GPUCommon.h" +#include "GPU/D3D11/FramebufferManagerD3D11.h" +#include "GPU/D3D11/DrawEngineD3D11.h" +#include "GPU/D3D11/TextureCacheD3D11.h" +#include "GPU/D3D11/DepalettizeShaderD3D11.h" +#include "GPU/Common/VertexDecoderCommon.h" + +namespace D3D11 { + + class ShaderManagerD3D11; + class LinkedShaderD3D11; + + class GPU_D3D11 : public GPUCommon { + public: + GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw); + ~GPU_D3D11(); + + void CheckGPUFeatures(); + void PreExecuteOp(u32 op, u32 diff) override; + void ExecuteOp(u32 op, u32 diff) override; + + void ReapplyGfxStateInternal() override; + void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override; + void BeginFrame() override; + void GetStats(char *buffer, size_t bufsize) override; + void ClearCacheNextFrame() override; + void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. + void DeviceRestore() override; + + void DumpNextFrame() override; + void DoState(PointerWrap &p) override; + + void ClearShaderCache() override; + bool DecodeTexture(u8 *dest, const GPUgstate &state) override { + return false; + } + bool FramebufferDirty() override; + bool FramebufferReallyDirty() override; + + void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override { + primaryInfo = reportingPrimaryInfo_; + fullInfo = reportingFullInfo_; + } + std::vector GetFramebufferList() override; + + bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes = -1) override; + bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override; + bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override; + bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override; + bool GetCurrentClut(GPUDebugBuffer &buffer) override; + bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; + bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) override; + + typedef void (GPU_D3D11::*CmdFunc)(u32 op, u32 diff); + struct CommandInfo { + uint64_t flags; + GPU_D3D11::CmdFunc func; + }; + + void Execute_Prim(u32 op, u32 diff); + void Execute_Bezier(u32 op, u32 diff); + void Execute_Spline(u32 op, u32 diff); + void Execute_VertexType(u32 op, u32 diff); + void Execute_VertexTypeSkinning(u32 op, u32 diff); + void Execute_TexSize0(u32 op, u32 diff); + void Execute_LoadClut(u32 op, u32 diff); + + // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. + std::vector DebugGetShaderIDs(DebugShaderType shader) override; + std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; + + protected: + void FastRunLoop(DisplayList &list) override; + void FinishDeferred() override; + + private: + void UpdateCmdInfo(); + + void Flush() { + drawEngine_.Flush(); + } + // void ApplyDrawState(int prim); + void CheckFlushOp(int cmd, u32 diff); + void BuildReportingInfo(); + + void InitClearInternal() override; + void BeginFrameInternal() override; + void CopyDisplayToOutputInternal() override; + + ID3D11Device *device_; + ID3D11DeviceContext *context_; + + FramebufferManagerD3D11 *framebufferManagerD3D11_; + TextureCacheD3D11 *textureCacheD3D11_; + DepalShaderCacheD3D11 depalShaderCache_; + DrawEngineD3D11 drawEngine_; + ShaderManagerD3D11 *shaderManagerD3D11_; + + static CommandInfo cmdInfo_[256]; + + int lastVsync_; + + std::string reportingPrimaryInfo_; + std::string reportingFullInfo_; + }; + +} // namespace D3D11 + +typedef D3D11::GPU_D3D11 D3D11_GPU; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/GPU/D3D11/TextureCacheD3D11.h b/GPU/D3D11/TextureCacheD3D11.h new file mode 100644 index 0000000000..49cc4a292e --- /dev/null +++ b/GPU/D3D11/TextureCacheD3D11.h @@ -0,0 +1,20 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +class TextureCacheD3D11 {}; \ No newline at end of file diff --git a/GPU/D3D11/VertexShaderGeneratorD3D11.h b/GPU/D3D11/VertexShaderGeneratorD3D11.h index 746f4a0ce1..d8936e9722 100644 --- a/GPU/D3D11/VertexShaderGeneratorD3D11.h +++ b/GPU/D3D11/VertexShaderGeneratorD3D11.h @@ -1,3 +1,20 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + #pragma once #include "GPU/Common/ShaderId.h" diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index 26c222da2a..deff4fdf70 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -29,6 +29,7 @@ #if defined(_WIN32) #include "GPU/Directx9/GPU_DX9.h" +#include "GPU/D3D11/GPU_D3D11.h" #endif GPUStatistics gpuStats; @@ -59,10 +60,18 @@ bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) { case GPUCORE_DIRECTX9: #if defined(_WIN32) SetGPU(new DIRECTX9_GPU(ctx, draw)); -#endif break; - case GPUCORE_DIRECTX11: +#else return false; +#endif + case GPUCORE_DIRECTX11: +#if defined(_WIN32) + // SetGPU(new D3D11_GPU(ctx, draw)); + // break; + return false; +#else + return false; +#endif case GPUCORE_VULKAN: #ifndef NO_VULKAN if (!ctx) { diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 2c509f8848..cd9fdeb5dd 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -203,8 +203,13 @@ + + + + + @@ -291,9 +296,14 @@ + + + + + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 0c498c3f8a..07bfddc62f 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -16,9 +16,6 @@ {88629970-4774-4122-b031-2128244b795c} - - {ba434472-5d5e-4b08-ab16-bfb7ec8e7068} - {0cbddc00-4aa3-41d0-bed2-a454d37f838e} @@ -237,6 +234,21 @@ D3D11 + + D3D11 + + + D3D11 + + + D3D11 + + + D3D11 + + + D3D11 + @@ -458,5 +470,20 @@ D3D11 + + D3D11 + + + D3D11 + + + D3D11 + + + D3D11 + + + D3D11 + \ No newline at end of file From ba95e0f4d93a315dffc1875f5ffb721803040c9d Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 8 Feb 2017 18:07:34 +0100 Subject: [PATCH 04/40] Initial stab at porting the DX9 backend to D3D11. Not working yet. --- GPU/Common/DepalettizeShaderCommon.cpp | 25 +- GPU/Common/DepalettizeShaderCommon.h | 8 +- GPU/Common/ShaderCommon.h | 10 + GPU/Common/TextureCacheCommon.h | 27 + GPU/D3D11/D3D11Util.cpp | 91 ++ GPU/D3D11/D3D11Util.h | 81 ++ GPU/D3D11/DepalettizeShaderD3D11.cpp | 175 +++ GPU/D3D11/DepalettizeShaderD3D11.h | 53 +- GPU/D3D11/DrawEngineD3D11.cpp | 926 +++++++++++++++ GPU/D3D11/DrawEngineD3D11.h | 230 +++- GPU/D3D11/FragmentShaderGeneratorD3D11.cpp | 21 +- GPU/D3D11/FramebufferManagerD3D11.cpp | 1033 +++++++++++++++++ GPU/D3D11/FramebufferManagerD3D11.h | 133 ++- GPU/D3D11/GPU_D3D11.cpp | 1004 +++++++++++++++- GPU/D3D11/GPU_D3D11.h | 176 ++- GPU/D3D11/ShaderManagerD3D11.cpp | 49 +- GPU/D3D11/ShaderManagerD3D11.h | 9 +- GPU/D3D11/StateMappingD3D11.cpp | 61 + GPU/D3D11/StencilBufferD3D11.cpp | 261 +++++ GPU/D3D11/TextureCacheD3D11.cpp | 1200 ++++++++++++++++++++ GPU/D3D11/TextureCacheD3D11.h | 111 +- GPU/D3D11/TextureScalerD3D11.cpp | 57 + GPU/D3D11/TextureScalerD3D11.h | 29 + GPU/D3D11/VertexShaderGeneratorD3D11.cpp | 22 +- GPU/Directx9/DepalettizeShaderDX9.h | 1 - GPU/Directx9/DrawEngineDX9.cpp | 2 +- GPU/Directx9/GPU_DX9.cpp | 4 +- GPU/Directx9/PixelShaderGeneratorDX9.cpp | 74 +- GPU/Directx9/PixelShaderGeneratorDX9.h | 3 +- GPU/Directx9/ShaderManagerDX9.cpp | 6 +- GPU/Directx9/ShaderManagerDX9.h | 4 +- GPU/Directx9/TextureCacheDX9.cpp | 2 - GPU/Directx9/TextureCacheDX9.h | 1 + GPU/Directx9/VertexShaderGeneratorDX9.cpp | 127 ++- GPU/Directx9/VertexShaderGeneratorDX9.h | 2 +- GPU/GLES/GPU_GLES.cpp | 6 +- GPU/GLES/ShaderManagerGLES.cpp | 6 +- GPU/GLES/ShaderManagerGLES.h | 6 +- GPU/GPU.cpp | 5 +- GPU/GPU.vcxproj | 5 + GPU/GPU.vcxproj.filters | 15 + GPU/Vulkan/TextureCacheVulkan.cpp | 9 +- GPU/Vulkan/TextureCacheVulkan.h | 22 - dx9sdk | 2 +- ext/native/thin3d/thin3d.h | 3 + ext/native/thin3d/thin3d_d3d11.cpp | 17 +- 46 files changed, 5835 insertions(+), 279 deletions(-) create mode 100644 GPU/D3D11/D3D11Util.cpp create mode 100644 GPU/D3D11/D3D11Util.h create mode 100644 GPU/D3D11/StencilBufferD3D11.cpp create mode 100644 GPU/D3D11/TextureScalerD3D11.cpp create mode 100644 GPU/D3D11/TextureScalerD3D11.h diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index c9b1481138..6e1d2f0151 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -29,7 +29,12 @@ // Uses integer instructions available since OpenGL 3.0. Suitable for ES 3.0 as well. void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLanguage language) { char *p = buffer; - if (language == GLSL_VULKAN) { + if (language == HLSL_D3D11) { + WRITE(p, "SamplerState texSamp : register(s0);\n"); + WRITE(p, "Texture2D tex : register(t0);\n"); + WRITE(p, "SamplerState palSamp : register(s1);\n"); + WRITE(p, "Texture2D pal : register(t1);\n"); + } else if (language == GLSL_VULKAN) { WRITE(p, "#version 140\n"); WRITE(p, "#extension GL_ARB_separate_shader_objects : enable\n"); WRITE(p, "#extension GL_ARB_shading_language_420pack : enable\n"); @@ -50,9 +55,14 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang WRITE(p, "uniform sampler2D pal;\n"); } - // TODO: Add support for integer textures. Though it hardly matters. - WRITE(p, "void main() {\n"); - WRITE(p, " vec4 color = texture(tex, v_texcoord0);\n"); + if (language == HLSL_D3D11) { + WRITE(p, "float4 main(in v_texcoord0 : TEXCOORD0) : SV_Target {\n"); + WRITE(p, " float4 color = texSamp.Sample(tex, v_texcoord0);\n"); + } else { + // TODO: Add support for integer textures. Though it hardly matters. + WRITE(p, "void main() {\n"); + WRITE(p, " vec4 color = texture(tex, v_texcoord0);\n"); + } int mask = gstate.getClutIndexMask(); int shift = gstate.getClutIndexShift(); @@ -110,7 +120,11 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang WRITE(p, ";\n"); } - WRITE(p, " fragColor0 = texture(pal, vec2((float(index) + 0.5) * (1.0 / %f), 0.0));\n", texturePixels); + if (language == HLSL_D3D11) { + WRITE(p, " fragColor0 = texSamp.Sample(pal, float2((float(index) + 0.5) * (1.0 / %f), 0.0));\n", texturePixels); + } else { + WRITE(p, " fragColor0 = texture(pal, vec2((float(index) + 0.5) * (1.0 / %f), 0.0));\n", texturePixels); + } WRITE(p, "}\n"); } @@ -262,6 +276,7 @@ void GenerateDepalShader(char *buffer, GEBufferFormat pixelFormat, ShaderLanguag break; case GLSL_300: case GLSL_VULKAN: + case HLSL_D3D11: GenerateDepalShader300(buffer, pixelFormat, language); break; case HLSL_DX9: diff --git a/GPU/Common/DepalettizeShaderCommon.h b/GPU/Common/DepalettizeShaderCommon.h index c49a65cdbf..7d2b02d113 100644 --- a/GPU/Common/DepalettizeShaderCommon.h +++ b/GPU/Common/DepalettizeShaderCommon.h @@ -18,12 +18,6 @@ #pragma once #include "GPU/ge_constants.h" - -enum ShaderLanguage { - GLSL_140, - GLSL_300, - GLSL_VULKAN, - HLSL_DX9, -}; +#include "GPU/Common/ShaderCommon.h" void GenerateDepalShader(char *buffer, GEBufferFormat pixelFormat, ShaderLanguage language); diff --git a/GPU/Common/ShaderCommon.h b/GPU/Common/ShaderCommon.h index 967d2f01ea..cef8ea7529 100644 --- a/GPU/Common/ShaderCommon.h +++ b/GPU/Common/ShaderCommon.h @@ -17,6 +17,16 @@ #pragma once +#include + +enum ShaderLanguage { + GLSL_140, + GLSL_300, + GLSL_VULKAN, + HLSL_DX9, + HLSL_D3D11, +}; + enum DebugShaderType { SHADER_TYPE_VERTEX = 0, SHADER_TYPE_FRAGMENT = 1, diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index eef5d7f641..6126c1f0f5 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -52,6 +52,30 @@ namespace Draw { class DrawContext; } +// Used by D3D11 and Vulkan, could be used by modern GL +struct SamplerCacheKey { + SamplerCacheKey() : fullKey(0) {} + + union { + u32 fullKey; + struct { + bool mipEnable : 1; + bool minFilt : 1; + bool mipFilt : 1; + bool magFilt : 1; + bool sClamp : 1; + bool tClamp : 1; + int lodBias : 4; + int maxLevel : 4; + }; + }; + + bool operator < (const SamplerCacheKey &other) const { + return fullKey < other.fullKey; + } +}; + + class FramebufferManagerCommon; class TextureCacheCommon { @@ -123,6 +147,9 @@ public: void *texturePtr; CachedTextureVulkan *vkTex; }; +#ifdef _WIN32 + void *textureView; // Used by D3D11 only for the shader resource view. +#endif int invalidHint; u32 fullhash; u32 cluthash; diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp new file mode 100644 index 0000000000..ca7e98be32 --- /dev/null +++ b/GPU/D3D11/D3D11Util.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include "thin3d/d3d11_loader.h" +#include "base/logging.h" + +#include "D3D11Util.h" + +static std::vector CompileShaderToBytecode(const char *code, size_t codeSize, const char *target) { + ID3DBlob *compiledCode = nullptr; + ID3DBlob *errorMsgs = nullptr; + HRESULT result = ptr_D3DCompile(code, codeSize, nullptr, nullptr, nullptr, "main", target, 0, 0, &compiledCode, &errorMsgs); + if (errorMsgs) { + std::string errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); + ELOG("%s: %s\n%s", SUCCEEDED(result) ? "warnings" : "errors", code, errors.c_str()); + errorMsgs->Release(); + } + if (compiledCode) { + const uint8_t *buf = (const uint8_t *)compiledCode->GetBufferPointer(); + std::vector compiled = std::vector(buf, buf + compiledCode->GetBufferSize()); + compiledCode->Release(); + return compiled; + } + return std::vector(); +} + +ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector *byteCodeOut) { + std::vector byteCode = CompileShaderToBytecode(code, codeSize, "vs_5_0"); + if (byteCode.empty()) + return nullptr; + ID3D11VertexShader *vs; + device->CreateVertexShader(byteCode.data(), byteCode.size(), nullptr, &vs); + if (byteCodeOut) + *byteCodeOut = byteCode; + return vs; +} + +ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize) { + std::vector byteCode = CompileShaderToBytecode(code, codeSize, "ps_5_0"); + if (byteCode.empty()) + return nullptr; + + ID3D11PixelShader *ps; + device->CreatePixelShader(byteCode.data(), byteCode.size(), nullptr, &ps); + return ps; +} + +void StockObjectsD3D11::Create(ID3D11Device *device) { + D3D11_BLEND_DESC blend_desc{}; + for (int i = 0; i < 16; i++) { + blend_desc.RenderTarget[0].RenderTargetWriteMask = i; + device->CreateBlendState(&blend_desc, &blendStateDisabledWithColorMask[i]); + } + D3D11_DEPTH_STENCIL_DESC depth_desc{}; + device->CreateDepthStencilState(&depth_desc, &depthStencilDisabled); + depth_desc.StencilEnable = TRUE; + 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.StencilFunc = D3D11_COMPARISON_ALWAYS; + depth_desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + device->CreateDepthStencilState(&depth_desc, &depthDisabledStencilWrite); + D3D11_RASTERIZER_DESC raster_desc{}; + raster_desc.FillMode = D3D11_FILL_SOLID; + raster_desc.CullMode = D3D11_CULL_NONE; + raster_desc.ScissorEnable = FALSE; + device->CreateRasterizerState(&raster_desc, &rasterStateNoCull); + D3D11_SAMPLER_DESC sampler_desc{}; + sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + device->CreateSamplerState(&sampler_desc, &samplerPoint2DWrap); + sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + device->CreateSamplerState(&sampler_desc, &samplerLinear2DWrap); +} + +void StockObjectsD3D11::Destroy() { + for (int i = 0; i < 16; i++) { + blendStateDisabledWithColorMask[i]->Release(); + } + depthStencilDisabled->Release(); + depthDisabledStencilWrite->Release(); + rasterStateNoCull->Release(); + samplerPoint2DWrap->Release(); + samplerLinear2DWrap->Release(); +} + +StockObjectsD3D11 stockD3D11; \ No newline at end of file diff --git a/GPU/D3D11/D3D11Util.h b/GPU/D3D11/D3D11Util.h new file mode 100644 index 0000000000..7e220e8958 --- /dev/null +++ b/GPU/D3D11/D3D11Util.h @@ -0,0 +1,81 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include +#include + +class PushBufferD3D11 { +public: + PushBufferD3D11(ID3D11Device *device, size_t size, D3D11_BIND_FLAG bindFlags) { + D3D11_BUFFER_DESC desc{}; + desc.BindFlags = bindFlags; + desc.ByteWidth = (UINT)size; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.Usage = D3D11_USAGE_DYNAMIC; + device->CreateBuffer(&desc, nullptr, &buffer_); + } + ~PushBufferD3D11() { + buffer_->Release(); + } + ID3D11Buffer *Buf() const { + return buffer_; + } + + // Should be done each frame + void Reset() { + pos_ = 0; + nextMapDiscard_ = true; + } + + uint8_t *BeginPush(ID3D11DeviceContext *context, int &offset, size_t size) { + D3D11_MAPPED_SUBRESOURCE map; + context->Map(buffer_, 0, nextMapDiscard_ ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map); + nextMapDiscard_ = false; + offset = (int)pos_; + uint8_t *retval = (uint8_t *)map.pData + pos_; + pos_ += size; + return retval; + } + void EndPush(ID3D11DeviceContext *context) { + context->Unmap(buffer_, 0); + } + +private: + ID3D11Buffer *buffer_ = nullptr; + size_t pos_ = 0; + bool nextMapDiscard_ = false; +}; + +ID3D11VertexShader *CreateVertexShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize, std::vector *byteCodeOut); +ID3D11PixelShader *CreatePixelShaderD3D11(ID3D11Device *device, const char *code, size_t codeSize); + +class StockObjectsD3D11 { +public: + void Create(ID3D11Device *device); + void Destroy(); + + ID3D11DepthStencilState *depthStencilDisabled; + ID3D11DepthStencilState *depthDisabledStencilWrite; + ID3D11BlendState *blendStateDisabledWithColorMask[16]; + ID3D11RasterizerState *rasterStateNoCull; + ID3D11SamplerState *samplerPoint2DWrap; + ID3D11SamplerState *samplerLinear2DWrap; +}; + +extern StockObjectsD3D11 stockD3D11; \ No newline at end of file diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp index e69de29bb2..cf88bf78fc 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.cpp +++ b/GPU/D3D11/DepalettizeShaderD3D11.cpp @@ -0,0 +1,175 @@ +// Copyright (c) 2014- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include + +#include "base/basictypes.h" +#include "base/logging.h" +#include "Common/Log.h" +#include "Core/Reporting.h" +#include "GPU/D3D11/TextureCacheD3D11.h" +#include "GPU/D3D11/DepalettizeShaderD3D11.h" +#include "GPU/D3D11/D3D11Util.h" +#include "GPU/Common/DepalettizeShaderCommon.h" +//#include "gfx/d3d9_shader.h" + +static const int DEPAL_TEXTURE_OLD_AGE = 120; + +#ifdef _WIN32 +#define SHADERLOG +#endif + +static const char *depalVShaderHLSL = +"struct VS_IN {\n" +" float3 a_position : POSITION;\n" +" float2 a_texcoord0 : TEXCOORD0;\n" +"};\n" +"struct VS_OUT {\n" +" float4 Position : SV_Position;\n" +" float2 Texcoord : TEXCOORD0;\n" +"};\n" +"VS_OUT main(VS_IN input) {\n" +" VS_OUT output;\n" +" output.Texcoord = input.a_texcoord0;\n" +" output.Position = float4(input.a_position, 1.0);\n" +" return output;\n" +"}\n"; + +static const D3D11_INPUT_ELEMENT_DESC g_DepalVertexElements[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, }, +}; + +DepalShaderCacheD3D11::DepalShaderCacheD3D11(ID3D11Device *device, ID3D11DeviceContext *context) + : device_(device), context_(context) { + std::string errorMessage; + std::vector vsByteCode; + vertexShader_ = CreateVertexShaderD3D11(device, depalVShaderHLSL, strlen(depalVShaderHLSL), &vsByteCode); + device_->CreateInputLayout(g_DepalVertexElements, ARRAY_SIZE(g_DepalVertexElements), vsByteCode.data(), vsByteCode.size(), &inputLayout_); + + D3D11_SAMPLER_DESC sampDesc{}; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.Filter = D3D11_FILTER_MINIMUM_MIN_MAG_MIP_POINT; + device_->CreateSamplerState(&sampDesc, &clutSampler); +} + +DepalShaderCacheD3D11::~DepalShaderCacheD3D11() { + Clear(); + if (vertexShader_) { + vertexShader_->Release(); + } + clutSampler->Release(); +} + +u32 DepalShaderCacheD3D11::GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) { + return (clutFormat & 0xFFFFFF) | (pixelFormat << 24); +} + +ID3D11ShaderResourceView *DepalShaderCacheD3D11::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutID, u32 *rawClut) { + const u32 realClutID = clutID ^ clutFormat; + + auto oldtex = texCache_.find(realClutID); + if (oldtex != texCache_.end()) { + oldtex->second->lastFrame = gpuStats.numFlips; + return oldtex->second->view; + } + + DXGI_FORMAT dstFmt = getClutDestFormatD3D11(clutFormat); + int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512; + + DepalTextureD3D11 *tex = new DepalTextureD3D11(); + // TODO: Look into 1D textures + + D3D11_TEXTURE2D_DESC desc{}; + desc.Width = texturePixels; + desc.Height = 1; + desc.ArraySize = 1; + desc.Format = dstFmt; + desc.Usage = D3D11_USAGE_IMMUTABLE; + + D3D11_SUBRESOURCE_DATA data{}; + data.pSysMem = rawClut; + // Regardless of format, the CLUT should always be 1024 bytes. + data.SysMemPitch = 1024; + HRESULT hr = device_->CreateTexture2D(&desc, &data, &tex->texture); + if (FAILED(hr)) { + ERROR_LOG(G3D, "Failed to create D3D texture for depal"); + delete tex; + return nullptr; + } + device_->CreateShaderResourceView(tex->texture, nullptr, &tex->view); + tex->lastFrame = gpuStats.numFlips; + texCache_[realClutID] = tex; + return tex->view; +} + +void DepalShaderCacheD3D11::Clear() { + for (auto shader = cache_.begin(); shader != cache_.end(); ++shader) { + shader->second->pixelShader->Release(); + delete shader->second; + } + cache_.clear(); + + for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) { + delete tex->second; + } + texCache_.clear(); +} + +void DepalShaderCacheD3D11::Decimate() { + for (auto tex = texCache_.begin(); tex != texCache_.end();) { + if (tex->second->lastFrame + DEPAL_TEXTURE_OLD_AGE < gpuStats.numFlips) { + delete tex->second; + texCache_.erase(tex++); + } else { + ++tex; + } + } +} + +ID3D11PixelShader *DepalShaderCacheD3D11::GetDepalettizePixelShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) { + u32 id = GenerateShaderID(clutFormat, pixelFormat); + + auto shader = cache_.find(id); + if (shader != cache_.end()) { + return shader->second->pixelShader; + } + + char *buffer = new char[2048]; + + GenerateDepalShader(buffer, pixelFormat, HLSL_D3D11); + + ID3D11PixelShader *pshader = CreatePixelShaderD3D11(device_, buffer, strlen(buffer)); + + if (!pshader) { + ERROR_LOG(G3D, "Failed to compile depal pixel shader"); + delete[] buffer; + return nullptr; + } + + DepalShaderD3D11 *depal = new DepalShaderD3D11(); + depal->pixelShader = pshader; + + cache_[id] = depal; + + delete[] buffer; + + return depal->pixelShader; +} \ No newline at end of file diff --git a/GPU/D3D11/DepalettizeShaderD3D11.h b/GPU/D3D11/DepalettizeShaderD3D11.h index 73d7e85b00..c4889b1669 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.h +++ b/GPU/D3D11/DepalettizeShaderD3D11.h @@ -15,6 +15,55 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#pragma once +#include +#include +#include +#include +#include "Common/CommonTypes.h" +#include "GPU/ge_constants.h" -class DepalShaderCacheD3D11 {}; \ No newline at end of file +class DepalShaderD3D11 { +public: + ID3D11PixelShader *pixelShader; +}; + +class DepalTextureD3D11 { +public: + ~DepalTextureD3D11() { + if (texture) + texture->Release(); + if (view) + view->Release(); + } + ID3D11Texture2D *texture; + ID3D11ShaderResourceView *view; + int lastFrame; +}; + +// Caches both shaders and palette textures. +class DepalShaderCacheD3D11 { +public: + DepalShaderCacheD3D11(ID3D11Device *device, ID3D11DeviceContext *context); + ~DepalShaderCacheD3D11(); + + // This also uploads the palette and binds the correct texture. + ID3D11PixelShader *GetDepalettizePixelShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat); + ID3D11VertexShader *GetDepalettizeVertexShader() { return vertexShader_; } + ID3D11InputLayout *GetInputLayout() { return inputLayout_; } + ID3D11ShaderResourceView *GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut); + ID3D11SamplerState *GetClutSampler() { return clutSampler; } + void Clear(); + void Decimate(); + +private: + u32 GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat); + + ID3D11Device *device_; + ID3D11DeviceContext *context_; + ID3D11VertexShader *vertexShader_ = nullptr; + ID3D11InputLayout *inputLayout_ = nullptr; + ID3D11SamplerState *clutSampler = nullptr; + + std::map cache_; + std::map texCache_; +}; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index e69de29bb2..b4a003f504 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -0,0 +1,926 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "base/logging.h" +#include "base/timeutil.h" + +#include "Common/MemoryUtil.h" +#include "Core/MemMap.h" +#include "Core/Host.h" +#include "Core/System.h" +#include "Core/Reporting.h" +#include "Core/Config.h" +#include "Core/CoreTiming.h" + +#include "GPU/Math3D.h" +#include "GPU/GPUState.h" +#include "GPU/ge_constants.h" + +#include "GPU/Common/TextureDecoder.h" +#include "GPU/Common/SplineCommon.h" +#include "GPU/Common/TransformCommon.h" +#include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/Common/SoftwareTransformCommon.h" +#include "GPU/D3D11/TextureCacheD3D11.h" +#include "GPU/D3D11/DrawEngineD3D11.h" +#include "GPU/D3D11/ShaderManagerD3D11.h" +#include "GPU/D3D11/GPU_D3D11.h" + +const D3D11_PRIMITIVE_TOPOLOGY glprim[8] = { + D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, + D3D11_PRIMITIVE_TOPOLOGY_LINELIST, + D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED, // Fans not supported + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Need expansion - though we could do it with geom shaders in most cases +}; + +enum { + TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex) +}; + +#define VERTEXCACHE_DECIMATION_INTERVAL 17 + +enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 }; + +static const D3D11_INPUT_ELEMENT_DESC TransformedVertexElements[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 }, +}; + +DrawEngineD3D11::DrawEngineD3D11(ID3D11Device *device, ID3D11DeviceContext *context) + : device_(device), + context_(context), + decodedVerts_(0), + prevPrim_(GE_PRIM_INVALID), + lastVType_(-1), + shaderManager_(0), + textureCache_(0), + framebufferManager_(0), + numDrawCalls(0), + vertexCountInDrawCalls(0), + decodeCounter_(0), + dcid_(0), + fboTexNeedBind_(false), + fboTexBound_(false) { + decOptions_.expandAllWeightsToFloat = true; + decOptions_.expand8BitNormalsToFloat = true; + + decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL; + // Allocate nicely aligned memory. Maybe graphics drivers will + // appreciate it. + // All this is a LOT of memory, need to see if we can cut down somehow. + decoded = (u8 *)AllocateMemoryPages(DECODED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); + decIndex = (u16 *)AllocateMemoryPages(DECODED_INDEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); + splineBuffer = (u8 *)AllocateMemoryPages(SPLINE_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); + transformed = (TransformedVertex *)AllocateMemoryPages(TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); + transformedExpanded = (TransformedVertex *)AllocateMemoryPages(3 * TRANSFORMED_VERTEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE); + + indexGen.Setup(decIndex); + + InitDeviceObjects(); + + tessDataTransfer = new TessellationDataTransferD3D11(); + transformedVertexDecl_ = nullptr; +} + +DrawEngineD3D11::~DrawEngineD3D11() { + if (transformedVertexDecl_) { + transformedVertexDecl_->Release(); + } + + DestroyDeviceObjects(); + FreeMemoryPages(decoded, DECODED_VERTEX_BUFFER_SIZE); + FreeMemoryPages(decIndex, DECODED_INDEX_BUFFER_SIZE); + FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE); + FreeMemoryPages(transformed, TRANSFORMED_VERTEX_BUFFER_SIZE); + FreeMemoryPages(transformedExpanded, 3 * TRANSFORMED_VERTEX_BUFFER_SIZE); + for (auto decl = vertexDeclMap_.begin(); decl != vertexDeclMap_.end(); ++decl) { + if (decl->second) { + decl->second->Release(); + } + } + + delete tessDataTransfer; +} + +void DrawEngineD3D11::InitDeviceObjects() { + +} + +void DrawEngineD3D11::DestroyDeviceObjects() { + ClearTrackedVertexArrays(); +} + +struct DeclTypeInfo { + DXGI_FORMAT type; + const char * name; +}; + +static const DeclTypeInfo VComp[] = { + { DXGI_FORMAT_UNKNOWN, "NULL" }, // DEC_NONE, + { DXGI_FORMAT_R32_FLOAT, "D3DDECLTYPE_FLOAT1 " }, // DEC_FLOAT_1, + { DXGI_FORMAT_R32G32_FLOAT, "D3DDECLTYPE_FLOAT2 " }, // DEC_FLOAT_2, + { DXGI_FORMAT_R32G32B32_FLOAT, "D3DDECLTYPE_FLOAT3 " }, // DEC_FLOAT_3, + { DXGI_FORMAT_R32G32B32A32_FLOAT, "D3DDECLTYPE_FLOAT4 " }, // DEC_FLOAT_4, + + { DXGI_FORMAT_R8G8B8A8_SNORM, "UNUSED" }, // DEC_S8_3, + + { DXGI_FORMAT_R16G16B16A16_SNORM, "D3DDECLTYPE_SHORT4N " }, // DEC_S16_3, + { DXGI_FORMAT_R8G8B8A8_UNORM, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_1, + { DXGI_FORMAT_R8G8B8A8_UNORM, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_2, + { DXGI_FORMAT_R8G8B8A8_UNORM, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_3, + { DXGI_FORMAT_R8G8B8A8_UNORM, "D3DDECLTYPE_UBYTE4N " }, // DEC_U8_4, + + { DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16_1" }, // DEC_U16_1, + { DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16_2" }, // DEC_U16_2, + { DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_3, + { DXGI_FORMAT_R16G16B16A16_UNORM ,"D3DDECLTYPE_USHORT4N "}, // DEC_U16_4, + { DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U8A_2"}, // DEC_U8A_2, + { DXGI_FORMAT_UNKNOWN, "UNUSED_DEC_U16A_2" }, // DEC_U16A_2, +}; + +static void VertexAttribSetup(D3D11_INPUT_ELEMENT_DESC * VertexElement, u8 fmt, u8 offset, const char *semantic, u8 semantic_index = 0) { + memset(VertexElement, 0, sizeof(D3D11_INPUT_ELEMENT_DESC)); + VertexElement->AlignedByteOffset = offset; + VertexElement->Format = VComp[fmt].type; + VertexElement->SemanticName = semantic; + VertexElement->SemanticIndex = semantic_index; +} + +ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshader, const DecVtxFormat &decFmt, u32 pspFmt) { + auto vertexDeclCached = vertexDeclMap_.find(pspFmt); + + if (vertexDeclCached == vertexDeclMap_.end()) { + D3D11_INPUT_ELEMENT_DESC VertexElements[8]; + D3D11_INPUT_ELEMENT_DESC *VertexElement = &VertexElements[0]; + + // Vertices Elements orders + // WEIGHT + if (decFmt.w0fmt != 0) { + VertexAttribSetup(VertexElement, decFmt.w0fmt, decFmt.w0off, "TEXCOORD", 1); + VertexElement++; + } + + if (decFmt.w1fmt != 0) { + VertexAttribSetup(VertexElement, decFmt.w1fmt, decFmt.w1off, "TEXCOORD", 2); + VertexElement++; + } + + // TC + if (decFmt.uvfmt != 0) { + VertexAttribSetup(VertexElement, decFmt.uvfmt, decFmt.uvoff, "TEXCOORD", 0); + VertexElement++; + } + + // COLOR + if (decFmt.c0fmt != 0) { + VertexAttribSetup(VertexElement, decFmt.c0fmt, decFmt.c0off, "COLOR", 0); + VertexElement++; + } + // Never used ? + if (decFmt.c1fmt != 0) { + VertexAttribSetup(VertexElement, decFmt.c1fmt, decFmt.c1off, "COLOR", 1); + VertexElement++; + } + + // NORMAL + if (decFmt.nrmfmt != 0) { + VertexAttribSetup(VertexElement, decFmt.nrmfmt, decFmt.nrmoff, "NORMAL", 0); + VertexElement++; + } + + // POSITION + // Always + VertexAttribSetup(VertexElement, decFmt.posfmt, decFmt.posoff, "POSITION", 0); + VertexElement++; + + // Create declaration + ID3D11InputLayout *inputLayout = nullptr; + HRESULT hr = device_->CreateInputLayout(VertexElements, VertexElement - VertexElements, vshader->bytecode().data(), vshader->bytecode().size(), &inputLayout); + if (FAILED(hr)) { + ERROR_LOG(G3D, "Failed to create input layout!"); + inputLayout = nullptr; + } + + // Add it to map + vertexDeclMap_[pspFmt] = inputLayout; + return inputLayout; + } else { + // Set it from map + return vertexDeclCached->second; + } +} + +void DrawEngineD3D11::SetupVertexDecoder(u32 vertType) { + SetupVertexDecoderInternal(vertType); +} + +inline void DrawEngineD3D11::SetupVertexDecoderInternal(u32 vertType) { + // As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it + // into the top of the verttype where there are unused bits. + const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24); + + // If vtype has changed, setup the vertex decoder. + if (vertTypeID != lastVType_) { + dec_ = GetVertexDecoder(vertTypeID); + lastVType_ = vertTypeID; + } +} + +void DrawEngineD3D11::SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) { + if (!indexGen.PrimCompatible(prevPrim_, prim) || numDrawCalls >= MAX_DEFERRED_DRAW_CALLS || vertexCountInDrawCalls + vertexCount > VERTEX_BUFFER_MAX) + Flush(); + + // TODO: Is this the right thing to do? + if (prim == GE_PRIM_KEEP_PREVIOUS) { + prim = prevPrim_ != GE_PRIM_INVALID ? prevPrim_ : GE_PRIM_POINTS; + } else { + prevPrim_ = prim; + } + + SetupVertexDecoderInternal(vertType); + + *bytesRead = vertexCount * dec_->VertexSize(); + + if ((vertexCount < 2 && prim > 0) || (vertexCount < 3 && prim > 2 && prim != GE_PRIM_RECTANGLES)) + return; + + DeferredDrawCall &dc = drawCalls[numDrawCalls]; + dc.verts = verts; + dc.inds = inds; + dc.vertType = vertType; + dc.indexType = (vertType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT; + dc.prim = prim; + dc.vertexCount = vertexCount; + + u32 dhash = dcid_; + dhash ^= (u32)(uintptr_t)verts; + dhash = __rotl(dhash, 13); + dhash ^= (u32)(uintptr_t)inds; + dhash = __rotl(dhash, 13); + dhash ^= (u32)vertType; + dhash = __rotl(dhash, 13); + dhash ^= (u32)vertexCount; + dhash = __rotl(dhash, 13); + dhash ^= (u32)prim; + dcid_ = dhash; + + if (inds) { + GetIndexBounds(inds, vertexCount, vertType, &dc.indexLowerBound, &dc.indexUpperBound); + } else { + dc.indexLowerBound = 0; + dc.indexUpperBound = vertexCount - 1; + } + + uvScale[numDrawCalls] = gstate_c.uv; + + numDrawCalls++; + vertexCountInDrawCalls += vertexCount; + + if (g_Config.bSoftwareSkinning && (vertType & GE_VTYPE_WEIGHT_MASK)) { + DecodeVertsStep(); + decodeCounter_++; + } + + if (prim == GE_PRIM_RECTANGLES && (gstate.getTextureAddress(0) & 0x3FFFFFFF) == (gstate.getFrameBufAddress() & 0x3FFFFFFF)) { + // Rendertarget == texture? + if (!g_Config.bDisableSlowFramebufEffects) { + gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); + Flush(); + } + } +} + +void DrawEngineD3D11::DecodeVerts() { + const UVScale origUV = gstate_c.uv; + for (; decodeCounter_ < numDrawCalls; decodeCounter_++) { + gstate_c.uv = uvScale[decodeCounter_]; + DecodeVertsStep(); + } + gstate_c.uv = origUV; + + // Sanity check + if (indexGen.Prim() < 0) { + ERROR_LOG_REPORT(G3D, "DecodeVerts: Failed to deduce prim: %i", indexGen.Prim()); + // Force to points (0) + indexGen.AddPrim(GE_PRIM_POINTS, 0); + } +} + +void DrawEngineD3D11::DecodeVertsStep() { + const int i = decodeCounter_; + + const DeferredDrawCall &dc = drawCalls[i]; + + indexGen.SetIndex(decodedVerts_); + int indexLowerBound = dc.indexLowerBound, indexUpperBound = dc.indexUpperBound; + + u32 indexType = dc.indexType; + void *inds = dc.inds; + if (indexType == GE_VTYPE_IDX_NONE >> GE_VTYPE_IDX_SHIFT) { + // Decode the verts and apply morphing. Simple. + dec_->DecodeVerts(decoded + decodedVerts_ * (int)dec_->GetDecVtxFmt().stride, + dc.verts, indexLowerBound, indexUpperBound); + decodedVerts_ += indexUpperBound - indexLowerBound + 1; + indexGen.AddPrim(dc.prim, dc.vertexCount); + } else { + // It's fairly common that games issue long sequences of PRIM calls, with differing + // inds pointer but the same base vertex pointer. We'd like to reuse vertices between + // these as much as possible, so we make sure here to combine as many as possible + // into one nice big drawcall, sharing data. + + // 1. Look ahead to find the max index, only looking as "matching" drawcalls. + // Expand the lower and upper bounds as we go. + int lastMatch = i; + const int total = numDrawCalls; + for (int j = i + 1; j < total; ++j) { + if (drawCalls[j].verts != dc.verts) + break; + if (memcmp(&uvScale[j], &uvScale[i], sizeof(uvScale[0])) != 0) + break; + + indexLowerBound = std::min(indexLowerBound, (int)drawCalls[j].indexLowerBound); + indexUpperBound = std::max(indexUpperBound, (int)drawCalls[j].indexUpperBound); + lastMatch = j; + } + + // 2. Loop through the drawcalls, translating indices as we go. + switch (indexType) { + case GE_VTYPE_IDX_8BIT >> GE_VTYPE_IDX_SHIFT: + for (int j = i; j <= lastMatch; j++) { + indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u8 *)drawCalls[j].inds, indexLowerBound); + } + break; + case GE_VTYPE_IDX_16BIT >> GE_VTYPE_IDX_SHIFT: + for (int j = i; j <= lastMatch; j++) { + indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u16_le *)drawCalls[j].inds, indexLowerBound); + } + break; + case GE_VTYPE_IDX_32BIT >> GE_VTYPE_IDX_SHIFT: + for (int j = i; j <= lastMatch; j++) { + indexGen.TranslatePrim(drawCalls[j].prim, drawCalls[j].vertexCount, (const u32_le *)drawCalls[j].inds, indexLowerBound); + } + break; + } + + const int vertexCount = indexUpperBound - indexLowerBound + 1; + + // This check is a workaround for Pangya Fantasy Golf, which sends bogus index data when switching items in "My Room" sometimes. + if (decodedVerts_ + vertexCount > VERTEX_BUFFER_MAX) { + return; + } + + // 3. Decode that range of vertex data. + dec_->DecodeVerts(decoded + decodedVerts_ * (int)dec_->GetDecVtxFmt().stride, + dc.verts, indexLowerBound, indexUpperBound); + decodedVerts_ += vertexCount; + + // 4. Advance indexgen vertex counter. + indexGen.Advance(vertexCount); + decodeCounter_ = lastMatch; + } +} + +inline u32 ComputeMiniHashRange(const void *ptr, size_t sz) { + // Switch to u32 units. + const u32 *p = (const u32 *)ptr; + sz >>= 2; + + if (sz > 100) { + size_t step = sz / 4; + u32 hash = 0; + for (size_t i = 0; i < sz; i += step) { + hash += DoReliableHash32(p + i, 100, 0x3A44B9C4); + } + return hash; + } else { + return p[0] + p[sz - 1]; + } +} + +u32 DrawEngineD3D11::ComputeMiniHash() { + u32 fullhash = 0; + const int vertexSize = dec_->GetDecVtxFmt().stride; + const int indexSize = IndexSize(dec_->VertexType()); + + int step; + if (numDrawCalls < 3) { + step = 1; + } else if (numDrawCalls < 8) { + step = 4; + } else { + step = numDrawCalls / 8; + } + for (int i = 0; i < numDrawCalls; i += step) { + const DeferredDrawCall &dc = drawCalls[i]; + if (!dc.inds) { + fullhash += ComputeMiniHashRange(dc.verts, vertexSize * dc.vertexCount); + } else { + int indexLowerBound = dc.indexLowerBound, indexUpperBound = dc.indexUpperBound; + fullhash += ComputeMiniHashRange((const u8 *)dc.verts + vertexSize * indexLowerBound, vertexSize * (indexUpperBound - indexLowerBound)); + fullhash += ComputeMiniHashRange(dc.inds, indexSize * dc.vertexCount); + } + } + + return fullhash; +} + +void DrawEngineD3D11::MarkUnreliable(VertexArrayInfoD3D11 *vai) { + vai->status = VertexArrayInfoD3D11::VAI_UNRELIABLE; + if (vai->vbo) { + vai->vbo->Release(); + vai->vbo = nullptr; + } + if (vai->ebo) { + vai->ebo->Release(); + vai->ebo = nullptr; + } +} + +ReliableHashType DrawEngineD3D11::ComputeHash() { + ReliableHashType fullhash = 0; + const int vertexSize = dec_->GetDecVtxFmt().stride; + const int indexSize = IndexSize(dec_->VertexType()); + + // TODO: Add some caps both for numDrawCalls and num verts to check? + // It is really very expensive to check all the vertex data so often. + for (int i = 0; i < numDrawCalls; i++) { + const DeferredDrawCall &dc = drawCalls[i]; + if (!dc.inds) { + fullhash += DoReliableHash((const char *)dc.verts, vertexSize * dc.vertexCount, 0x1DE8CAC4); + } else { + int indexLowerBound = dc.indexLowerBound, indexUpperBound = dc.indexUpperBound; + int j = i + 1; + int lastMatch = i; + while (j < numDrawCalls) { + if (drawCalls[j].verts != dc.verts) + break; + indexLowerBound = std::min(indexLowerBound, (int)dc.indexLowerBound); + indexUpperBound = std::max(indexUpperBound, (int)dc.indexUpperBound); + lastMatch = j; + j++; + } + // This could get seriously expensive with sparse indices. Need to combine hashing ranges the same way + // we do when drawing. + fullhash += DoReliableHash((const char *)dc.verts + vertexSize * indexLowerBound, + vertexSize * (indexUpperBound - indexLowerBound), 0x029F3EE1); + // Hm, we will miss some indices when combining above, but meh, it should be fine. + fullhash += DoReliableHash((const char *)dc.inds, indexSize * dc.vertexCount, 0x955FD1CA); + i = lastMatch; + } + } + if (uvScale) { + fullhash += DoReliableHash(&uvScale[0], sizeof(uvScale[0]) * numDrawCalls, 0x0123e658); + } + + return fullhash; +} + +void DrawEngineD3D11::ClearTrackedVertexArrays() { + for (auto vai = vai_.begin(); vai != vai_.end(); vai++) { + delete vai->second; + } + vai_.clear(); +} + +void DrawEngineD3D11::DecimateTrackedVertexArrays() { + if (--decimationCounter_ <= 0) { + decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL; + } else { + return; + } + + const int threshold = gpuStats.numFlips - VAI_KILL_AGE; + const int unreliableThreshold = gpuStats.numFlips - VAI_UNRELIABLE_KILL_AGE; + int unreliableLeft = VAI_UNRELIABLE_KILL_MAX; + for (auto iter = vai_.begin(); iter != vai_.end(); ) { + bool kill; + if (iter->second->status == VertexArrayInfoD3D11::VAI_UNRELIABLE) { + // We limit killing unreliable so we don't rehash too often. + kill = iter->second->lastFrame < unreliableThreshold && --unreliableLeft >= 0; + } else { + kill = iter->second->lastFrame < threshold; + } + if (kill) { + delete iter->second; + vai_.erase(iter++); + } else { + ++iter; + } + } + + // Enable if you want to see vertex decoders in the log output. Need a better way. +#if 0 + char buffer[16384]; + for (std::map::iterator dec = decoderMap_.begin(); dec != decoderMap_.end(); ++dec) { + char *ptr = buffer; + ptr += dec->second->ToString(ptr); + // *ptr++ = '\n'; + NOTICE_LOG(G3D, buffer); + } +#endif +} + +VertexArrayInfoD3D11::~VertexArrayInfoD3D11() { + if (vbo) { + vbo->Release(); + } + if (ebo) { + ebo->Release(); + } +} + +static uint32_t SwapRB(uint32_t c) { + return (c & 0xFF00FF00) | ((c >> 16) & 0xFF) | ((c << 16) & 0xFF0000); +} + +// The inline wrapper in the header checks for numDrawCalls == 0 +void DrawEngineD3D11::DoFlush() { + gpuStats.numFlushes++; + gpuStats.numTrackedVertexArrays = (int)vai_.size(); + + // This is not done on every drawcall, we should collect vertex data + // until critical state changes. That's when we draw (flush). + + GEPrimitiveType prim = prevPrim_; + ApplyDrawState(prim); + + bool useHWTransform = CanUseHardwareTransform(prim); + + if (useHWTransform) { + ID3D11Buffer *vb_ = nullptr; + ID3D11Buffer *ib_ = nullptr; + + int vertexCount = 0; + int maxIndex = 0; + bool useElements = true; + + // Cannot cache vertex data with morph enabled. + bool useCache = g_Config.bVertexCache && !(lastVType_ & GE_VTYPE_MORPHCOUNT_MASK); + // Also avoid caching when software skinning. + if (g_Config.bSoftwareSkinning && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) + useCache = false; + + if (useCache) { + u32 id = dcid_ ^ gstate.getUVGenMode(); // This can have an effect on which UV decoder we need to use! And hence what the decoded data will look like. See #9263 + auto iter = vai_.find(id); + VertexArrayInfoD3D11 *vai; + if (iter != vai_.end()) { + // We've seen this before. Could have been a cached draw. + vai = iter->second; + } else { + vai = new VertexArrayInfoD3D11(); + vai_[id] = vai; + } + + switch (vai->status) { + case VertexArrayInfoD3D11::VAI_NEW: + { + // Haven't seen this one before. + ReliableHashType dataHash = ComputeHash(); + vai->hash = dataHash; + vai->minihash = ComputeMiniHash(); + vai->status = VertexArrayInfoD3D11::VAI_HASHING; + vai->drawsUntilNextFullHash = 0; + DecodeVerts(); // writes to indexGen + vai->numVerts = indexGen.VertexCount(); + vai->prim = indexGen.Prim(); + vai->maxIndex = indexGen.MaxIndex(); + vai->flags = gstate_c.vertexFullAlpha ? VAI11_FLAG_VERTEXFULLALPHA : 0; + + goto rotateVBO; + } + + // Hashing - still gaining confidence about the buffer. + // But if we get this far it's likely to be worth creating a vertex buffer. + case VertexArrayInfoD3D11::VAI_HASHING: + { + vai->numDraws++; + if (vai->lastFrame != gpuStats.numFlips) { + vai->numFrames++; + } + if (vai->drawsUntilNextFullHash == 0) { + // Let's try to skip a full hash if mini would fail. + const u32 newMiniHash = ComputeMiniHash(); + ReliableHashType newHash = vai->hash; + if (newMiniHash == vai->minihash) { + newHash = ComputeHash(); + } + if (newMiniHash != vai->minihash || newHash != vai->hash) { + MarkUnreliable(vai); + DecodeVerts(); + goto rotateVBO; + } + if (vai->numVerts > 64) { + // exponential backoff up to 16 draws, then every 24 + vai->drawsUntilNextFullHash = std::min(24, vai->numFrames); + } else { + // Lower numbers seem much more likely to change. + vai->drawsUntilNextFullHash = 0; + } + // TODO: tweak + //if (vai->numFrames > 1000) { + // vai->status = VertexArrayInfo::VAI_RELIABLE; + //} + } else { + vai->drawsUntilNextFullHash--; + u32 newMiniHash = ComputeMiniHash(); + if (newMiniHash != vai->minihash) { + MarkUnreliable(vai); + DecodeVerts(); + goto rotateVBO; + } + } + + if (vai->vbo == 0) { + DecodeVerts(); + vai->numVerts = indexGen.VertexCount(); + vai->prim = indexGen.Prim(); + vai->maxIndex = indexGen.MaxIndex(); + vai->flags = gstate_c.vertexFullAlpha ? VAI11_FLAG_VERTEXFULLALPHA : 0; + useElements = !indexGen.SeenOnlyPurePrims(); + if (!useElements && indexGen.PureCount()) { + vai->numVerts = indexGen.PureCount(); + } + + _dbg_assert_msg_(G3D, gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); + + // TODO: Combine these two into one buffer? + void * pVb; + u32 size = dec_->GetDecVtxFmt().stride * indexGen.MaxIndex(); + D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_VERTEX_BUFFER, D3D11_CPU_ACCESS_WRITE }; + D3D11_SUBRESOURCE_DATA data{ decoded }; + device_->CreateBuffer(&desc, &data, &vai->vbo); + if (useElements) { + void * pIb; + u32 size = sizeof(short) * indexGen.VertexCount(); + D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_INDEX_BUFFER, D3D11_CPU_ACCESS_WRITE }; + D3D11_SUBRESOURCE_DATA data{ decoded }; + device_->CreateBuffer(&desc, &data, &vai->ebo); + } else { + vai->ebo = 0; + } + } else { + gpuStats.numCachedDrawCalls++; + useElements = vai->ebo ? true : false; + gpuStats.numCachedVertsDrawn += vai->numVerts; + gstate_c.vertexFullAlpha = vai->flags & VAI11_FLAG_VERTEXFULLALPHA; + } + vb_ = vai->vbo; + ib_ = vai->ebo; + vertexCount = vai->numVerts; + maxIndex = vai->maxIndex; + prim = static_cast(vai->prim); + break; + } + + // Reliable - we don't even bother hashing anymore. Right now we don't go here until after a very long time. + case VertexArrayInfoD3D11::VAI_RELIABLE: + { + vai->numDraws++; + if (vai->lastFrame != gpuStats.numFlips) { + vai->numFrames++; + } + gpuStats.numCachedDrawCalls++; + gpuStats.numCachedVertsDrawn += vai->numVerts; + vb_ = vai->vbo; + ib_ = vai->ebo; + + vertexCount = vai->numVerts; + + maxIndex = vai->maxIndex; + prim = static_cast(vai->prim); + + gstate_c.vertexFullAlpha = vai->flags & VAI11_FLAG_VERTEXFULLALPHA; + break; + } + + case VertexArrayInfoD3D11::VAI_UNRELIABLE: + { + vai->numDraws++; + if (vai->lastFrame != gpuStats.numFlips) { + vai->numFrames++; + } + DecodeVerts(); + goto rotateVBO; + } + } + + vai->lastFrame = gpuStats.numFlips; + } else { + DecodeVerts(); +rotateVBO: + gpuStats.numUncachedVertsDrawn += indexGen.VertexCount(); + useElements = !indexGen.SeenOnlyPurePrims(); + vertexCount = indexGen.VertexCount(); + maxIndex = indexGen.MaxIndex(); + if (!useElements && indexGen.PureCount()) { + vertexCount = indexGen.PureCount(); + } + prim = indexGen.Prim(); + } + + VERBOSE_LOG(G3D, "Flush prim %i! %i verts in one go", prim, vertexCount); + bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; + if (gstate.isModeThrough()) { + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255); + } else { + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255); + } + + ApplyDrawStateLate(false, 0); + + D3D11VertexShader *vshader; + D3D11FragmentShader *fshader; + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform); + ID3D11InputLayout *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); + + context_->IASetInputLayout(pHardwareVertexDecl); + if (!vb_) { + // Push! + int vOffset; + // pushVerts_->BeginPush(context_, offset, ) + if (useElements) { + // context_->DrawIndexedPrimitiveUP(glprim[prim], 0, maxIndex + 1, D3DPrimCount(glprim[prim], vertexCount), decIndex, D3DFMT_INDEX16, decoded, dec_->GetDecVtxFmt().stride); + } else { + // context_->DrawPrimitiveUP(glprim[prim], D3DPrimCount(glprim[prim], vertexCount), decoded, dec_->GetDecVtxFmt().stride); + } + } else { + UINT stride = dec_->GetDecVtxFmt().stride; + UINT offset = 0; + context_->IASetVertexBuffers(0, 1, &vb_, &stride, &offset); + context_->IASetPrimitiveTopology(glprim[prim]); + if (useElements) { + context_->IASetIndexBuffer(ib_, DXGI_FORMAT_R16_UINT, 0); + context_->DrawIndexed(vertexCount, 0, 0); + } else { + context_->Draw(vertexCount, 0); + } + } + } else { + DecodeVerts(); + bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE; + if (gstate.isModeThrough()) { + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255); + } else { + gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255); + } + + gpuStats.numUncachedVertsDrawn += indexGen.VertexCount(); + prim = indexGen.Prim(); + // Undo the strip optimization, not supported by the SW code yet. + if (prim == GE_PRIM_TRIANGLE_STRIP) + prim = GE_PRIM_TRIANGLES; + VERBOSE_LOG(G3D, "Flush prim %i SW! %i verts in one go", prim, indexGen.VertexCount()); + + int numTrans = 0; + bool drawIndexed = false; + u16 *inds = decIndex; + TransformedVertex *drawBuffer = NULL; + SoftwareTransformResult result; + memset(&result, 0, sizeof(result)); + + SoftwareTransformParams params; + memset(¶ms, 0, sizeof(params)); + params.decoded = decoded; + params.transformed = transformed; + params.transformedExpanded = transformedExpanded; + params.fbman = framebufferManager_; + params.texCache = textureCache_; + params.allowSeparateAlphaClear = true; + + int maxIndex = indexGen.MaxIndex(); + SoftwareTransform( + prim, indexGen.VertexCount(), + dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(), + maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result); + + ApplyDrawStateLate(result.setStencil, result.stencilValue); + + D3D11VertexShader *vshader; + D3D11FragmentShader *fshader; + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false); + + // TODO: Implement clear properly when possible. Colormask no longer applies to clearing unfortunately (though wonder if it ever did in hardware..) which makes it trickier. + if (result.action == SW_DRAW_PRIMITIVES || result.action == SW_CLEAR) { + // TODO: Add a post-transform cache here for multi-RECTANGLES only. + // Might help for text drawing. + + // these spam the gDebugger log. + const int vertexSize = sizeof(transformed[0]); + + // This is so weird. Why do we need the shader bytecode to create an input layout?? + // Well, at least all vshaders for pretransformed data will have one single layout so we can share it. + if (!transformedVertexDecl_) { + device_->CreateInputLayout(TransformedVertexElements, 4, vshader->bytecode().data(), vshader->bytecode().size(), &transformedVertexDecl_); + } + + context_->IASetInputLayout(transformedVertexDecl_); + ID3D11Buffer *pushVertData = pushVerts_->Buf(); + ID3D11Buffer *pushIndexData = pushInds_->Buf(); + UINT strides = sizeof(TransformedVertex); + context_->IASetVertexBuffers(0, 1, &pushVertData, &strides, nullptr); + if (drawIndexed) { + context_->IASetIndexBuffer(pushIndexData, DXGI_FORMAT_R16_UINT, 0); + context_->DrawIndexed(numTrans, 0, 0); + // context_->DrawIndexedPrimitiveUP(glprim[prim], 0, maxIndex, numTrans, inds, DXGI_FORMAT_R16_UINT, drawBuffer, sizeof(TransformedVertex)); + } else { + // context_->DrawPrimitiveUP(glprim[prim], D3DPrimCount(glprim[prim], numTrans), drawBuffer, sizeof(TransformedVertex)); + context_->Draw(numTrans, 0); + } + } /*else if (result.action == SW_CLEAR) { + u32 clearColor = result.color; + float clearDepth = result.depth; + + UINT depthClearFlag = 0; + + bool clearColor = gstate.isClearModeColorMask(); + if (gstate.isClearModeAlphaMask()) depthClearFlag |= D3D11_CLEAR_STENCIL; + if (gstate.isClearModeDepthMask()) depthClearFlag |= D3D11_CLEAR_DEPTH; + + if (clearColor) { + framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); + } + if (depthClearFlag & D3D11_CLEAR_DEPTH) { + framebufferManager_->SetDepthUpdated(); + } + + int colorMask = 0; + if (clearColor) + colorMask |= 7; + if (depthClearFlag & D3D11_CLEAR_STENCIL) { + colorMask |= 8; + } + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[colorMask], nullptr, 0xFFFFFFFF); + + device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24); + + int scissorX1 = gstate.getScissorX1(); + int scissorY1 = gstate.getScissorY1(); + int scissorX2 = gstate.getScissorX2() + 1; + int scissorY2 = gstate.getScissorY2() + 1; + framebufferManager_->SetSafeSize(scissorX2, scissorY2); + + if (g_Config.bBlockTransferGPU && (gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { + ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); + } + }*/ + } + + gpuStats.numDrawCalls += numDrawCalls; + gpuStats.numVertsSubmitted += vertexCountInDrawCalls; + + indexGen.Reset(); + decodedVerts_ = 0; + numDrawCalls = 0; + vertexCountInDrawCalls = 0; + decodeCounter_ = 0; + dcid_ = 0; + prevPrim_ = GE_PRIM_INVALID; + gstate_c.vertexFullAlpha = true; + framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); + + // Now seems as good a time as any to reset the min/max coords, which we may examine later. + gstate_c.vertBounds.minU = 512; + gstate_c.vertBounds.minV = 512; + gstate_c.vertBounds.maxU = 0; + gstate_c.vertBounds.maxV = 0; + + host->GPUNotifyDraw(); +} + +void DrawEngineD3D11::Resized() { + decJitCache_->Clear(); + lastVType_ = -1; + dec_ = NULL; + for (auto iter = decoderMap_.begin(); iter != decoderMap_.end(); iter++) { + delete iter->second; + } + decoderMap_.clear(); +} + +bool DrawEngineD3D11::IsCodePtrVertexDecoder(const u8 *ptr) const { + return decJitCache_->IsInSpace(ptr); +} + +void DrawEngineD3D11::TessellationDataTransferD3D11::SendDataToShader(const float * pos, const float * tex, const float * col, int size, bool hasColor, bool hasTexCoords) +{ +} diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index a0222a9a33..6ccf017085 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017- PPSSPP Project. +// Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -17,7 +17,229 @@ #pragma once -class DrawEngineD3D11 { +#include + +#include + +#include "GPU/GPUState.h" +#include "GPU/Common/GPUDebugInterface.h" +#include "GPU/Common/IndexGenerator.h" +#include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/Common/DrawEngineCommon.h" +#include "GPU/Common/GPUStateUtils.h" +#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" +#include "GPU/D3D11/D3D11Util.h" + +struct DecVtxFormat; +struct UVScale; + +class D3D11VertexShader; +class ShaderManagerD3D11; +class TextureCacheD3D11; +class FramebufferManagerD3D11; + +// States transitions: +// On creation: DRAWN_NEW +// DRAWN_NEW -> DRAWN_HASHING +// DRAWN_HASHING -> DRAWN_RELIABLE +// DRAWN_HASHING -> DRAWN_UNRELIABLE +// DRAWN_ONCE -> UNRELIABLE +// DRAWN_RELIABLE -> DRAWN_SAFE +// UNRELIABLE -> death +// DRAWN_ONCE -> death +// DRAWN_RELIABLE -> death + +enum { + VAI11_FLAG_VERTEXFULLALPHA = 1, +}; + +// Avoiding the full include of TextureDecoder.h. +#if (defined(_M_SSE) && defined(_M_X64)) || defined(ARM64) +typedef u64 ReliableHashType; +#else +typedef u32 ReliableHashType; +#endif + +// Try to keep this POD. +class VertexArrayInfoD3D11 { public: - void Flush() {} -}; \ No newline at end of file + VertexArrayInfoD3D11() { + status = VAI_NEW; + vbo = 0; + ebo = 0; + prim = GE_PRIM_INVALID; + numDraws = 0; + numFrames = 0; + lastFrame = gpuStats.numFlips; + numVerts = 0; + drawsUntilNextFullHash = 0; + flags = 0; + } + ~VertexArrayInfoD3D11(); + + enum Status { + VAI_NEW, + VAI_HASHING, + VAI_RELIABLE, // cache, don't hash + VAI_UNRELIABLE, // never cache + }; + + ReliableHashType hash; + u32 minihash; + + Status status; + + ID3D11Buffer *vbo; + ID3D11Buffer *ebo; + + // Precalculated parameter for drawRangeElements + u16 numVerts; + u16 maxIndex; + s8 prim; + + // ID information + int numDraws; + int numFrames; + int lastFrame; // So that we can forget. + u16 drawsUntilNextFullHash; + u8 flags; +}; + +// Handles transform, lighting and drawing. +class DrawEngineD3D11 : public DrawEngineCommon { +public: + DrawEngineD3D11(ID3D11Device *device, ID3D11DeviceContext *context); + virtual ~DrawEngineD3D11(); + + void SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead); + + void SetShaderManager(ShaderManagerD3D11 *shaderManager) { + shaderManager_ = shaderManager; + } + void SetTextureCache(TextureCacheD3D11 *textureCache) { + textureCache_ = textureCache; + } + void SetFramebufferManager(FramebufferManagerD3D11 *fbManager) { + framebufferManager_ = fbManager; + } + void InitDeviceObjects(); + void DestroyDeviceObjects(); + void GLLost() {}; + + void Resized(); // TODO: Call + + void DecimateTrackedVertexArrays(); + void ClearTrackedVertexArrays(); + + void SetupVertexDecoder(u32 vertType); + void SetupVertexDecoderInternal(u32 vertType); + + // So that this can be inlined + void Flush() { + if (!numDrawCalls) + return; + DoFlush(); + } + + void FinishDeferred() { + if (!numDrawCalls) + return; + DecodeVerts(); + } + + bool IsCodePtrVertexDecoder(const u8 *ptr) const; + + void DispatchFlush() override { Flush(); } + void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) override { + SubmitPrim(verts, inds, prim, vertexCount, vertType, bytesRead); + } + +private: + void DecodeVerts(); + void DecodeVertsStep(); + void DoFlush(); + + void ApplyDrawState(int prim); + void ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef); + bool ApplyShaderBlending(); + void ResetShaderBlending(); + + ID3D11InputLayout *SetupDecFmtForDraw(D3D11VertexShader *vshader, const DecVtxFormat &decFmt, u32 pspFmt); + + u32 ComputeMiniHash(); + ReliableHashType ComputeHash(); // Reads deferred vertex data. + void MarkUnreliable(VertexArrayInfoD3D11 *vai); + + ID3D11Device *device_; + ID3D11DeviceContext *context_; + + // Defer all vertex decoding to a Flush, so that we can hash and cache the + // generated buffers without having to redecode them every time. + struct DeferredDrawCall { + void *verts; + void *inds; + u32 vertType; + u8 indexType; + s8 prim; + u32 vertexCount; + u16 indexLowerBound; + u16 indexUpperBound; + }; + + // Vertex collector state + IndexGenerator indexGen; + int decodedVerts_; + GEPrimitiveType prevPrim_; + + u32 lastVType_; + + TransformedVertex *transformed; + TransformedVertex *transformedExpanded; + + std::unordered_map vai_; + std::unordered_map vertexDeclMap_; + + // SimpleVertex + ID3D11InputLayout *transformedVertexDecl_; + + // Other + ShaderManagerD3D11 *shaderManager_; + TextureCacheD3D11 *textureCache_; + FramebufferManagerD3D11 *framebufferManager_; + + // Pushbuffers + PushBufferD3D11 *pushVerts_; + PushBufferD3D11 *pushInds_; + + enum { MAX_DEFERRED_DRAW_CALLS = 128 }; + + DeferredDrawCall drawCalls[MAX_DEFERRED_DRAW_CALLS]; + int numDrawCalls; + int vertexCountInDrawCalls; + + int decimationCounter_; + int decodeCounter_; + u32 dcid_; + + UVScale uvScale[MAX_DEFERRED_DRAW_CALLS]; + + bool fboTexNeedBind_; + bool fboTexBound_; + + // D3D11 state object caches + std::map blendCache_; + std::map depthStencilCache_; + std::map rasterCache_; + + // Hardware tessellation + class TessellationDataTransferD3D11 : public TessellationDataTransfer { + private: + int data_tex[3]; + public: + TessellationDataTransferD3D11() : TessellationDataTransfer(), data_tex() { + } + ~TessellationDataTransferD3D11() { + } + void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) override; + }; +}; diff --git a/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp b/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp index 86eac7c3ea..49340df4b1 100644 --- a/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp +++ b/GPU/D3D11/FragmentShaderGeneratorD3D11.cpp @@ -1,5 +1,24 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "GPU/Common/ShaderCommon.h" #include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" +#include "GPU/Directx9/PixelShaderGeneratorDX9.h" void GenerateFragmentShaderD3D11(const ShaderID &id, char *buffer) { - + DX9::GenerateFragmentShaderHLSL(id, buffer, HLSL_D3D11); } diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index e69de29bb2..2cb9ed711b 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -0,0 +1,1033 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "math/lin/matrix4x4.h" +#include "ext/native/thin3d/thin3d.h" + +#include "Common/ColorConv.h" +#include "Core/Host.h" +#include "Core/MemMap.h" +#include "Core/Config.h" +#include "Core/System.h" +#include "Core/Reporting.h" +#include "GPU/ge_constants.h" +#include "GPU/GPUState.h" +#include "GPU/Debugger/Stepping.h" + +#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/TextureDecoder.h" +#include "GPU/D3D11/FramebufferManagerD3D11.h" +#include "GPU/D3D11/ShaderManagerD3D11.h" +#include "GPU/D3D11/TextureCacheD3D11.h" +#include "GPU/D3D11/DrawEngineD3D11.h" + +#include "ext/native/thin3d/thin3d.h" + +#include + +#ifdef _M_SSE +#include +#endif + +static const char * vscode = + "struct VS_IN {\n" + " float4 ObjPos : POSITION;\n" + " float2 Uv : TEXCOORD0;\n" + "};" + "struct VS_OUT {\n" + " float4 ProjPos : SV_Position;\n" + " float2 Uv : TEXCOORD0;\n" + "};\n" + "VS_OUT main(VS_IN In) {\n" + " VS_OUT Out;\n" + " Out.ProjPos = In.ObjPos;\n" + " Out.Uv = In.Uv;\n" + " return Out;\n" + "}\n"; + +//-------------------------------------------------------------------------------------- +// Pixel shader +//-------------------------------------------------------------------------------------- +static const char * pscode = + "SamplerState samp : register(s0);\n" + "Texture2D tex : register(t0);\n" + "struct PS_IN {\n" + " float2 Uv : TEXCOORD0;\n" + "};\n" + "float4 main( PS_IN In ) : SV_Target {\n" + " float4 c = tex.Sample(samp, In.Uv);\n" + " return c;\n" + "}\n"; + +static const D3D11_INPUT_ELEMENT_DESC g_FramebufferVertexElements[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, }, +}; + +void FramebufferManagerD3D11::ClearBuffer(bool keepState) { + draw_->Clear(Draw::ClearFlag::COLOR | Draw::ClearFlag::DEPTH | Draw::ClearFlag::STENCIL, 0, ToScaledDepth(0), 0); +} + +void FramebufferManagerD3D11::DisableState() { + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF); + context_->RSSetState(stockD3D11.rasterStateNoCull); + context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0xFF); +} + +FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) + : FramebufferManagerCommon(draw), + drawPixelsTex_(0), + convBuf(0), + stencilUploadPS_(nullptr), + stencilUploadVS_(nullptr), + stencilUploadFailed_(false) { + + device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE); + context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); + + std::vector bytecode; + + std::string errorMsg; + pFramebufferVertexShader_ = CreateVertexShaderD3D11(device_, vscode, strlen(vscode), &bytecode); + pFramebufferPixelShader_ = CreatePixelShaderD3D11(device_, pscode, strlen(pscode)); + device_->CreateInputLayout(g_FramebufferVertexElements, ARRAY_SIZE(g_FramebufferVertexElements), bytecode.data(), bytecode.size(), &pFramebufferVertexDecl_); + + float coord[20] = { + -1.0f,-1.0f, 0, 0,0, + 1.0f,-1.0f, 0, 0,0, + 1.0f,1.0f, 0, 0,0, + -1.0f,1.0f, 0, 0,0, + }; + D3D11_BUFFER_DESC vb{}; + vb.ByteWidth = 20 * 4; + vb.Usage = D3D11_USAGE_IMMUTABLE; + vb.CPUAccessFlags = 0; +} + +FramebufferManagerD3D11::~FramebufferManagerD3D11() { + if (pFramebufferVertexShader_) { + pFramebufferVertexShader_->Release(); + pFramebufferVertexShader_ = nullptr; + } + if (pFramebufferPixelShader_) { + pFramebufferPixelShader_->Release(); + pFramebufferPixelShader_ = nullptr; + } + pFramebufferVertexDecl_->Release(); + if (drawPixelsTex_) { + drawPixelsTex_->Release(); + } + for (auto it = tempFBOs_.begin(), end = tempFBOs_.end(); it != end; ++it) { + delete it->second.fbo; + } + delete[] convBuf; + if (stencilUploadPS_) { + stencilUploadPS_->Release(); + } + if (stencilUploadVS_) { + stencilUploadVS_->Release(); + } +} + +void FramebufferManagerD3D11::SetTextureCache(TextureCacheD3D11 *tc) { + textureCacheD3D11_ = tc; + textureCache_ = tc; +} + +void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) { + u8 *convBuf = NULL; + + // TODO: Check / use D3DCAPS2_DYNAMICTEXTURES? + if (drawPixelsTex_ && (drawPixelsTexW_ != width || drawPixelsTexH_ != height)) { + drawPixelsTex_->Release(); + drawPixelsTex_ = nullptr; + } + + if (!drawPixelsTex_) { + int usage = 0; + D3D11_TEXTURE2D_DESC desc{}; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.Width = width; + desc.Height = height; + device_->CreateTexture2D(&desc, nullptr, &drawPixelsTex_); + device_->CreateShaderResourceView(drawPixelsTex_, nullptr, &drawPixelsTexView_); + drawPixelsTexW_ = width; + drawPixelsTexH_ = height; + } + + if (!drawPixelsTex_) { + return; + } + + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(drawPixelsTex_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + + convBuf = (u8*)map.pData; + + // Final format is BGRA(directx) + if (srcPixelFormat != GE_FORMAT_8888 || srcStride != 512) { + for (int y = 0; y < height; y++) { + switch (srcPixelFormat) { + case GE_FORMAT_565: + { + const u16_le *src = (const u16_le *)srcPixels + srcStride * y; + u32 *dst = (u32 *)(convBuf + map.RowPitch * y); + ConvertRGB565ToBGRA8888(dst, src, width); + } + break; + // faster + case GE_FORMAT_5551: + { + const u16_le *src = (const u16_le *)srcPixels + srcStride * y; + u32 *dst = (u32 *)(convBuf + map.RowPitch * y); + ConvertRGBA5551ToBGRA8888(dst, src, width); + } + break; + case GE_FORMAT_4444: + { + const u16_le *src = (const u16_le *)srcPixels + srcStride * y; + u8 *dst = (u8 *)(convBuf + map.RowPitch * y); + ConvertRGBA4444ToBGRA8888((u32 *)dst, src, width); + } + break; + + case GE_FORMAT_8888: + { + const u32_le *src = (const u32_le *)srcPixels + srcStride * y; + u32 *dst = (u32 *)(convBuf + map.RowPitch * y); + ConvertRGBA8888ToBGRA8888(dst, src, width); + } + break; + } + } + } else { + for (int y = 0; y < height; y++) { + const u32_le *src = (const u32_le *)srcPixels + srcStride * y; + u32 *dst = (u32 *)(convBuf + map.RowPitch * y); + ConvertRGBA8888ToBGRA8888(dst, src, width); + } + } + + context_->Unmap(drawPixelsTex_, 0); + // D3DXSaveTextureToFile("game:\\cc.png", D3DXIFF_PNG, drawPixelsTex_, NULL); +} + +void FramebufferManagerD3D11::DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) { + if (useBufferedRendering_ && vfb && vfb->fbo) { + draw_->BindFramebufferAsRenderTarget(vfb->fbo); + D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }; + context_->RSSetViewports(1, &vp); + } else { + float x, y, w, h; + CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL); + D3D11_VIEWPORT vp{ x, y, w, h, 0.0f, 1.0f }; + context_->RSSetViewports(1, &vp); + } + MakePixelTexture(srcPixels, srcPixelFormat, srcStride, width, height); + DisableState(); + context_->PSSetShaderResources(0, 1, &drawPixelsTexView_); + DrawActiveTexture(dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, 0.0f, 0.0f, 1.0f, 1.0f, ROTATION_LOCKED_HORIZONTAL, true); + textureCacheD3D11_->ForgetLastTexture(); + // context_->RSSetViewports(1, &vp); +} + +void FramebufferManagerD3D11::DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, bool applyPostShader) { + MakePixelTexture(srcPixels, srcPixelFormat, srcStride, 512, 272); + DisableState(); + + // This might draw directly at the backbuffer (if so, applyPostShader is set) so if there's a post shader, we need to apply it here. + // Should try to unify this path with the regular path somehow, but this simple solution works for most of the post shaders + // (it always runs at output resolution so FXAA may look odd). + float x, y, w, h; + int uvRotation = (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL; + CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, uvRotation); + context_->PSSetShaderResources(0, 1, &drawPixelsTexView_); + DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, 0.0f, 0.0f, 480.0f / 512.0f, 1.0f, uvRotation, g_Config.iBufFilter == SCALE_LINEAR); +} + +void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, bool linearFilter) { + // TODO: StretchRect instead? + float coord[20] = { + x,y,0, u0,v0, + x + w,y,0, u1,v0, + x + w,y + h,0, u1,v1, + x,y + h,0, u0,v1, + }; + + static const short indices[4] = { 0, 1, 3, 2 }; + + if (uvRotation != ROTATION_LOCKED_HORIZONTAL) { + float temp[8]; + int rotation = 0; + switch (uvRotation) { + case ROTATION_LOCKED_HORIZONTAL180: rotation = 2; break; + case ROTATION_LOCKED_VERTICAL: rotation = 1; break; + case ROTATION_LOCKED_VERTICAL180: rotation = 3; break; + } + + for (int i = 0; i < 4; i++) { + temp[i * 2] = coord[((i + rotation) & 3) * 5 + 3]; + temp[i * 2 + 1] = coord[((i + rotation) & 3) * 5 + 4]; + } + + for (int i = 0; i < 4; i++) { + coord[i * 5 + 3] = temp[i * 2]; + coord[i * 5 + 4] = temp[i * 2 + 1]; + } + } + + float invDestW = 1.0f / (destW * 0.5f); + float invDestH = 1.0f / (destH * 0.5f); + float halfPixelX = invDestW * 0.5f; + float halfPixelY = invDestH * 0.5f; + for (int i = 0; i < 4; i++) { + coord[i * 5] = coord[i * 5] * invDestW - 1.0f - halfPixelX; + coord[i * 5 + 1] = -(coord[i * 5 + 1] * invDestH - 1.0f - halfPixelY); + } + + context_->RSSetState(stockD3D11.rasterStateNoCull); + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF); + context_->IASetInputLayout(pFramebufferVertexDecl_); + context_->PSSetShader(pFramebufferPixelShader_, 0, 0); + context_->VSSetShader(pFramebufferVertexShader_, 0, 0); + context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context_->PSSetSamplers(0, 1, linearFilter ? &stockD3D11.samplerLinear2DWrap : &stockD3D11.samplerPoint2DWrap); + + // TODO: DrawRectBuffer ? + shaderManager_->DirtyLastShader(); + context_->Draw(2, 0); +} + +void FramebufferManagerD3D11::RebindFramebuffer() { + if (currentRenderVfb_ && currentRenderVfb_->fbo) { + draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo); + } else { + draw_->BindBackbufferAsRenderTarget(); + } +} + +void FramebufferManagerD3D11::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) { + if (!useBufferedRendering_ || !vfb->fbo) { + return; + } + + draw_->BindFramebufferAsRenderTarget(vfb->fbo); + + // Technically, we should at this point re-interpret the bytes of the old format to the new. + // That might get tricky, and could cause unnecessary slowness in some games. + // For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts. + // (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.) + // + // The best way to do this may ultimately be to create a new FBO (combine with any resize?) + // and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex + // to exactly reproduce in 4444 and 8888 formats. + + if (old == GE_FORMAT_565) { + context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0], nullptr, 0xFFFFFFFF); + context_->RSSetState(stockD3D11.rasterStateNoCull); + context_->IASetInputLayout(pFramebufferVertexDecl_); + context_->PSSetShader(pFramebufferPixelShader_, nullptr, 0); + context_->VSSetShader(pFramebufferVertexShader_, nullptr, 0); + context_->IASetVertexBuffers(0, 1, &vbFullScreenRect_, &vbFullScreenStride_, &vbFullScreenOffset_); + shaderManager_->DirtyLastShader(); + D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }; + context_->RSSetViewports(1, &vp); + context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context_->Draw(2, 0); + } + + RebindFramebuffer(); +} + +static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { + size_t x = 0; + +#ifdef _M_SSE + size_t sseSize = (c / 4) * 4; + const __m128i srcMask = _mm_set1_epi32(0x00FFFFFF); + const __m128i dstMask = _mm_set1_epi32(0xFF000000); + __m128i *dst = (__m128i *)dstp; + const __m128i *src = (const __m128i *)srcp; + + for (; x < sseSize; x += 4) { + const __m128i bits24 = _mm_and_si128(_mm_load_si128(src), srcMask); + const __m128i bits8 = _mm_and_si128(_mm_load_si128(dst), dstMask); + _mm_store_si128(dst, _mm_or_si128(bits24, bits8)); + dst++; + src++; + } +#endif + + // Copy the remaining pixels that didn't fit in SSE. + for (; x < c; ++x) { + memcpy(dstp + x, srcp + x, 3); + } +} + +void FramebufferManagerD3D11::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { + if (g_Config.bDisableSlowFramebufEffects) { + return; + } + /* + bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0; + bool matchingSize = src->width == dst->width && src->height == dst->height; + if (matchingDepthBuffer && matchingSize) { + // Doesn't work. Use a shader maybe? + draw_->BindBackbufferAsRenderTarget(); + + 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(); + }*/ +} + +void FramebufferManagerD3D11::BindFramebufferColor(int stage, VirtualFramebuffer *framebuffer, int flags) { + if (framebuffer == NULL) { + framebuffer = currentRenderVfb_; + } + + if (!framebuffer->fbo || !useBufferedRendering_) { + context_->PSSetShaderResources(stage, 1, nullptr); + gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; + return; + } + + // currentRenderVfb_ will always be set when this is called, except from the GE debugger. + // Let's just not bother with the copy in that case. + bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0; + if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) { + skipCopy = true; + } + // Currently rendering to this framebuffer. Need to make a copy. + if (!skipCopy && currentRenderVfb_ && framebuffer->fb_address == gstate.getFrameBufRawAddress()) { + // TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size. + Draw::Framebuffer *renderCopy = GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, (Draw::FBColorDepth)framebuffer->colorDepth); + if (renderCopy) { + VirtualFramebuffer copyInfo = *framebuffer; + copyInfo.fbo = renderCopy; + + int x = 0; + int y = 0; + int w = framebuffer->drawnWidth; + int h = framebuffer->drawnHeight; + + // If max is not > min, we probably could not detect it. Skip. + // See the vertex decoder, where this is updated. + if ((flags & BINDFBCOLOR_MAY_COPY_WITH_UV) == BINDFBCOLOR_MAY_COPY_WITH_UV && gstate_c.vertBounds.maxU > gstate_c.vertBounds.minU) { + x = gstate_c.vertBounds.minU; + y = gstate_c.vertBounds.minV; + w = gstate_c.vertBounds.maxU - x; + h = gstate_c.vertBounds.maxV - y; + + // If we bound a framebuffer, apply the byte offset as pixels to the copy too. + if (flags & BINDFBCOLOR_APPLY_TEX_OFFSET) { + x += gstate_c.curTextureXOffset; + y += gstate_c.curTextureYOffset; + } + } + + BlitFramebuffer(©Info, x, y, framebuffer, x, y, w, h, 0); + + RebindFramebuffer(); + draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0); + } else { + draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); + } + } else { + draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); + } +} + +void FramebufferManagerD3D11::CopyDisplayToOutput() { + DownloadFramebufferOnSwitch(currentRenderVfb_); + + draw_->BindBackbufferAsRenderTarget(); + currentRenderVfb_ = 0; + + if (displayFramebufPtr_ == 0) { + DEBUG_LOG(SCEGE, "Display disabled, displaying only black"); + // No framebuffer to display! Clear to black. + ClearBuffer(); + return; + } + + if (useBufferedRendering_) { + // In buffered, we no longer clear the backbuffer before we start rendering. + ClearBuffer(); + D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, 0.0f, 1.0f }; + context_->RSSetViewports(1, &vp); + } + + u32 offsetX = 0; + u32 offsetY = 0; + + VirtualFramebuffer *vfb = GetVFBAt(displayFramebufPtr_); + if (!vfb) { + // Let's search for a framebuf within this range. + const u32 addr = (displayFramebufPtr_ & 0x03FFFFFF) | 0x04000000; + for (size_t i = 0; i < vfbs_.size(); ++i) { + VirtualFramebuffer *v = vfbs_[i]; + const u32 v_addr = (v->fb_address & 0x03FFFFFF) | 0x04000000; + const u32 v_size = FramebufferByteSize(v); + if (addr >= v_addr && addr < v_addr + v_size) { + const u32 dstBpp = v->format == GE_FORMAT_8888 ? 4 : 2; + const u32 v_offsetX = ((addr - v_addr) / dstBpp) % v->fb_stride; + const u32 v_offsetY = ((addr - v_addr) / dstBpp) / v->fb_stride; + // We have enough space there for the display, right? + if (v_offsetX + 480 >(u32)v->fb_stride || v->bufferHeight < v_offsetY + 272) { + continue; + } + // Check for the closest one. + if (offsetY == 0 || offsetY > v_offsetY) { + offsetX = v_offsetX; + offsetY = v_offsetY; + vfb = v; + } + } + } + + if (vfb) { + // Okay, we found one above. + INFO_LOG_REPORT_ONCE(displayoffset, HLE, "Rendering from framebuf with offset %08x -> %08x+%dx%d", addr, vfb->fb_address, offsetX, offsetY); + } + } + + if (vfb && vfb->format != displayFormat_) { + if (vfb->last_frame_render + FBO_OLD_AGE < gpuStats.numFlips) { + // The game probably switched formats on us. + vfb->format = displayFormat_; + } else { + vfb = 0; + } + } + + if (!vfb) { + if (Memory::IsValidAddress(displayFramebufPtr_)) { + // The game is displaying something directly from RAM. In GTA, it's decoded video. + + // First check that it's not a known RAM copy of a VRAM framebuffer though, as in MotoGP + for (auto iter = knownFramebufferRAMCopies_.begin(); iter != knownFramebufferRAMCopies_.end(); ++iter) { + if (iter->second == displayFramebufPtr_) { + vfb = GetVFBAt(iter->first); + } + } + + if (!vfb) { + // Just a pointer to plain memory to draw. Draw it. + DrawFramebufferToOutput(Memory::GetPointer(displayFramebufPtr_), displayFormat_, displayStride_, true); + return; + } + } else { + DEBUG_LOG(SCEGE, "Found no FBO to display! displayFBPtr = %08x", displayFramebufPtr_); + // No framebuffer to display! Clear to black. If buffered, we already did that. + if (!useBufferedRendering_) + ClearBuffer(); + return; + } + } + + vfb->usageFlags |= FB_USAGE_DISPLAYED_FRAMEBUFFER; + vfb->last_frame_displayed = gpuStats.numFlips; + vfb->dirtyAfterDisplay = false; + vfb->reallyDirtyAfterDisplay = false; + + if (prevDisplayFramebuf_ != displayFramebuf_) { + prevPrevDisplayFramebuf_ = prevDisplayFramebuf_; + } + if (displayFramebuf_ != vfb) { + prevDisplayFramebuf_ = displayFramebuf_; + } + displayFramebuf_ = vfb; + + if (vfb->fbo) { + DEBUG_LOG(SCEGE, "Displaying FBO %08x", vfb->fb_address); + DisableState(); + draw_->BindFramebufferAsTexture(vfb->fbo, 0, Draw::FB_COLOR_BIT, 0); + + // Output coordinates + float x, y, w, h; + int uvRotation = (g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) ? g_Config.iInternalScreenRotation : ROTATION_LOCKED_HORIZONTAL; + CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, uvRotation); + + const float u0 = offsetX / (float)vfb->bufferWidth; + const float v0 = offsetY / (float)vfb->bufferHeight; + const float u1 = (480.0f + offsetX) / (float)vfb->bufferWidth; + const float v1 = (272.0f + offsetY) / (float)vfb->bufferHeight; + + if (1) { + const u32 rw = PSP_CoreParameter().pixelWidth; + const u32 rh = PSP_CoreParameter().pixelHeight; + bool result = draw_->BlitFramebuffer(vfb->fbo, + (LONG)(u0 * vfb->renderWidth), (LONG)(v0 * vfb->renderHeight), (LONG)(u1 * vfb->renderWidth), (LONG)(v1 * vfb->renderHeight), + nullptr, + (LONG)(x * rw / w), (LONG)(y * rh / h), (LONG)((x + w) * rw / w), (LONG)((y + h) * rh / h), + Draw::FB_COLOR_BIT, + g_Config.iBufFilter == SCALE_LINEAR ? Draw::FB_BLIT_LINEAR : Draw::FB_BLIT_NEAREST); + if (!result) { + ERROR_LOG_REPORT_ONCE(blit_fail, G3D, "fbo_blit_color failed on display"); + D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, 0.0f, 1.0f }; + context_->RSSetViewports(1, &vp); + DrawActiveTexture(x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, u0, v0, u1, v1, uvRotation, g_Config.iBufFilter == SCALE_LINEAR); + } + } + /* + else if (usePostShader_ && extraFBOs_.size() == 1 && !postShaderAtOutputResolution_) { + // An additional pass, post-processing shader to the extra FBO. + BindFramebufferAsRenderTarget(extraFBOs_[0]); + int fbo_w, fbo_h; + fbo_get_dimensions(extraFBOs_[0], &fbo_w, &fbo_h); + DXSetViewport(0, 0, fbo_w, fbo_h); + DrawActiveTexture(colorTexture, 0, 0, fbo_w, fbo_h, fbo_w, fbo_h, true, 1.0f, 1.0f, postShaderProgram_); + + fbo_unbind(); + + // Use the extra FBO, with applied post-processing shader, as a texture. + // fbo_bind_color_as_texture(extraFBOs_[0], 0); + if (extraFBOs_.size() == 0) { + ERROR_LOG(G3D, "WTF?"); + return; + } + colorTexture = fbo_get_color_texture(extraFBOs_[0]); + DXSetViewport(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); + // These are in the output display coordinates + DrawActiveTexture(colorTexture, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, true, 480.0f / (float)vfb->width, 272.0f / (float)vfb->height); + } else { + // Use post-shader, but run shader at output resolution. + DXSetViewport(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); + // These are in the output display coordinates + DrawActiveTexture(colorTexture, x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, true, 480.0f / (float)vfb->width, 272.0f / (float)vfb->height, postShaderProgram_); + } + */ + } + // gstate_c.Dirty(DIRTY_VIEWPORT_STATE); +} + +void FramebufferManagerD3D11::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) { + if (vfb) { + // We'll pseudo-blit framebuffers here to get a resized version of vfb. + VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb); + OptimizeDownloadRange(vfb, x, y, w, h); + BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0); + + PackFramebufferD3D11_(nvfb, x, y, w, h); + + textureCacheD3D11_->ForgetLastTexture(); + RebindFramebuffer(); + } +} + +void FramebufferManagerD3D11::DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) { + VirtualFramebuffer *vfb = GetVFBAt(fb_address); + if (vfb && vfb->fb_stride != 0) { + const u32 bpp = vfb->drawnFormat == GE_FORMAT_8888 ? 4 : 2; + int x = 0; + int y = 0; + int pixels = loadBytes / bpp; + // The height will be 1 for each stride or part thereof. + int w = std::min(pixels % vfb->fb_stride, (int)vfb->width); + int h = std::min((pixels + vfb->fb_stride - 1) / vfb->fb_stride, (int)vfb->height); + + // We might still have a pending draw to the fb in question, flush if so. + FlushBeforeCopy(); + + // No need to download if we already have it. + if (!vfb->memoryUpdated && vfb->clutUpdatedBytes < loadBytes) { + // We intentionally don't call OptimizeDownloadRange() here - we don't want to over download. + // CLUT framebuffers are often incorrectly estimated in size. + if (x == 0 && y == 0 && w == vfb->width && h == vfb->height) { + vfb->memoryUpdated = true; + } + vfb->clutUpdatedBytes = loadBytes; + + // We'll pseudo-blit framebuffers here to get a resized version of vfb. + VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb); + BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0); + + PackFramebufferD3D11_(nvfb, x, y, w, h); + + textureCacheD3D11_->ForgetLastTexture(); + RebindFramebuffer(); + } + } +} + +bool FramebufferManagerD3D11::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) { + nvfb->colorDepth = Draw::FBO_8888; + + nvfb->fbo = draw_->CreateFramebuffer({ nvfb->width, nvfb->height, 1, 1, true, (Draw::FBColorDepth)nvfb->colorDepth }); + if (!(nvfb->fbo)) { + ERROR_LOG(SCEGE, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight); + return false; + } + + draw_->BindFramebufferAsRenderTarget(nvfb->fbo); + ClearBuffer(); + return true; +} + +void FramebufferManagerD3D11::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) { + // Nothing to do here. +} + +void FramebufferManagerD3D11::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) { + if (!dst->fbo || !src->fbo || !useBufferedRendering_) { + // This can happen if they recently switched from non-buffered. + draw_->BindBackbufferAsRenderTarget(); + return; + } + + float srcXFactor = (float)src->renderWidth / (float)src->bufferWidth; + float srcYFactor = (float)src->renderHeight / (float)src->bufferHeight; + const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; + if (srcBpp != bpp && bpp != 0) { + srcXFactor = (srcXFactor * bpp) / srcBpp; + } + int srcX1 = srcX * srcXFactor; + int srcX2 = (srcX + w) * srcXFactor; + int srcY1 = srcY * srcYFactor; + int srcY2 = (srcY + h) * srcYFactor; + + float dstXFactor = (float)dst->renderWidth / (float)dst->bufferWidth; + float dstYFactor = (float)dst->renderHeight / (float)dst->bufferHeight; + const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; + if (dstBpp != bpp && bpp != 0) { + dstXFactor = (dstXFactor * bpp) / dstBpp; + } + int dstX1 = dstX * dstXFactor; + int dstX2 = (dstX + w) * dstXFactor; + int dstY1 = dstY * dstYFactor; + int dstY2 = (dstY + h) * dstYFactor; + + // Direct3D 9 doesn't support rect -> self. + Draw::Framebuffer *srcFBO = src->fbo; + if (src == dst) { + Draw::Framebuffer *tempFBO = GetTempFBO(src->renderWidth, src->renderHeight, (Draw::FBColorDepth)src->colorDepth); + bool result = draw_->BlitFramebuffer( + src->fbo, srcX1, srcY1, srcX2, srcY2, + tempFBO, dstX1, dstY1, dstX2, dstY2, + Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST); + if (result) { + srcFBO = tempFBO; + } + } + bool result = draw_->BlitFramebuffer( + srcFBO, srcX1, srcY1, srcX2, srcY2, + dst->fbo, dstX1, dstY1, dstX2, dstY2, + Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST); + if (!result) { + ERROR_LOG_REPORT(G3D, "fbo_blit_color failed in blit: %08x (%08x -> %08x)", src->fb_address, dst->fb_address); + } +} + +// TODO: SSE/NEON +// Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :) +void ConvertFromRGBA8888(u8 *dst, u8 *src, u32 dstStride, u32 srcStride, u32 width, u32 height, GEBufferFormat format) { + // Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP. + const u32 *src32 = (const u32 *)src; + + if (format == GE_FORMAT_8888) { + u32 *dst32 = (u32 *)dst; + if (src == dst) { + return; + } else { + for (u32 y = 0; y < height; ++y) { + ConvertBGRA8888ToRGBA8888(dst32, src32, width); + src32 += srcStride; + dst32 += dstStride; + } + } + } else { + // But here it shouldn't matter if they do intersect + u16 *dst16 = (u16 *)dst; + switch (format) { + case GE_FORMAT_565: // BGR 565 + for (u32 y = 0; y < height; ++y) { + ConvertBGRA8888ToRGB565(dst16, src32, width); + src32 += srcStride; + dst16 += dstStride; + } + break; + case GE_FORMAT_5551: // ABGR 1555 + for (u32 y = 0; y < height; ++y) { + ConvertBGRA8888ToRGBA5551(dst16, src32, width); + src32 += srcStride; + dst16 += dstStride; + } + break; + case GE_FORMAT_4444: // ABGR 4444 + for (u32 y = 0; y < height; ++y) { + ConvertBGRA8888ToRGBA4444(dst16, src32, width); + src32 += srcStride; + dst16 += dstStride; + } + break; + case GE_FORMAT_8888: + case GE_FORMAT_INVALID: + // Not possible. + break; + } + } +} + +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(); + return; + } + + const u32 fb_address = (0x04000000) | vfb->fb_address; + const int dstBpp = vfb->format == GE_FORMAT_8888 ? 4 : 2; + + // We always need to convert from the framebuffer native format. + // 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); + + LPDIRECT3DSURFACE9 offscreen = GetOffscreenSurface(renderTarget, vfb); + if (offscreen) { + HRESULT hr = pD3Ddevice->GetRenderTargetData(renderTarget, offscreen); + if (SUCCEEDED(hr)) { + D3DLOCKED_RECT locked; + u32 widthFactor = vfb->renderWidth / vfb->bufferWidth; + u32 heightFactor = vfb->renderHeight / vfb->bufferHeight; + RECT rect = { (LONG)(x * widthFactor), (LONG)(y * heightFactor), (LONG)((x + w) * widthFactor), (LONG)((y + h) * heightFactor) }; + hr = offscreen->LockRect(&locked, &rect, D3DLOCK_READONLY); + if (SUCCEEDED(hr)) { + // TODO: Handle the other formats? We don't currently create them, I think. + const int dstByteOffset = (y * vfb->fb_stride + x) * dstBpp; + // Pixel size always 4 here because we always request BGRA8888. + ConvertFromRGBA8888(Memory::GetPointer(fb_address + dstByteOffset), (u8 *)locked.pBits, vfb->fb_stride, locked.Pitch / 4, w, h, vfb->format); + offscreen->UnlockRect(); + } else { + ERROR_LOG_REPORT(G3D, "Unable to lock rect from %08x: %d,%d %dx%d of %dx%d", fb_address, rect.left, rect.top, rect.right, rect.bottom, vfb->renderWidth, vfb->renderHeight); + } + } else { + ERROR_LOG_REPORT(G3D, "Unable to download render target data from %08x", fb_address); + } + } + */ +} + +void FramebufferManagerD3D11::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) { + if (!vfb->fbo) { + ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackDepthbuffer: vfb->fbo == 0"); + return; + } + + // We always read the depth buffer in 24_8 format. + const u32 z_address = (0x04000000) | vfb->z_address; + + /* + DEBUG_LOG(SCEGE, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); + + LPDIRECT3DTEXTURE9 tex = (LPDIRECT3DTEXTURE9)draw_->GetFramebufferAPITexture(vfb->fbo, Draw::FB_DEPTH_BIT, 0); + if (tex) { + D3DSURFACE_DESC desc; + D3DLOCKED_RECT locked; + tex->GetLevelDesc(0, &desc); + RECT rect = { 0, 0, (LONG)desc.Width, (LONG)desc.Height }; + HRESULT hr = tex->LockRect(0, &locked, &rect, D3DLOCK_READONLY); + + if (SUCCEEDED(hr)) { + const int dstByteOffset = y * vfb->fb_stride * sizeof(s16); + const u32 *packed = (const u32 *)locked.pBits; + u16 *depth = (u16 *)Memory::GetPointer(z_address); + + // TODO: Optimize. + for (int yp = 0; yp < h; ++yp) { + for (int xp = 0; xp < w; ++xp) { + const int offset = (yp + y) & vfb->z_stride + x + xp; + + float scaled = FromScaledDepth((packed[offset] & 0x00FFFFFF) * (1.0f / 16777215.0f)); + if (scaled <= 0.0f) { + depth[offset] = 0; + } else if (scaled >= 65535.0f) { + depth[offset] = 65535; + } else { + depth[offset] = (int)scaled; + } + } + } + + tex->UnlockRect(0); + } else { + ERROR_LOG_REPORT(G3D, "Unable to lock rect from depth %08x: %d,%d %dx%d of %dx%d", vfb->fb_address, rect.left, rect.top, rect.right, rect.bottom, vfb->renderWidth, vfb->renderHeight); + } + } else { + ERROR_LOG_REPORT(G3D, "Unable to download render target depth from %08x", vfb->fb_address); + }*/ +} + +void FramebufferManagerD3D11::EndFrame() { + if (resized_) { + DestroyAllFBOs(false); + // Actually, auto mode should be more granular... + // Round up to a zoom factor for the render size. + int zoom = g_Config.iInternalResolution; + if (zoom == 0) { // auto mode + // Use the longest dimension + if (!g_Config.IsPortrait()) { + zoom = (PSP_CoreParameter().pixelWidth + 479) / 480; + } else { + zoom = (PSP_CoreParameter().pixelHeight + 479) / 480; + } + } + if (zoom <= 1) + zoom = 1; + + if (g_Config.IsPortrait()) { + PSP_CoreParameter().renderWidth = 272 * zoom; + PSP_CoreParameter().renderHeight = 480 * zoom; + } else { + PSP_CoreParameter().renderWidth = 480 * zoom; + PSP_CoreParameter().renderHeight = 272 * zoom; + } + + UpdateSize(); + // Seems related - if you're ok with numbers all the time, show some more :) + if (g_Config.iShowFPSCounter != 0) { + ShowScreenResolution(); + } + resized_ = false; + } +} + +void FramebufferManagerD3D11::DeviceLost() { + DestroyAllFBOs(false); + resized_ = false; +} + +std::vector FramebufferManagerD3D11::GetFramebufferList() { + std::vector list; + + for (size_t i = 0; i < vfbs_.size(); ++i) { + VirtualFramebuffer *vfb = vfbs_[i]; + + FramebufferInfo info; + info.fb_address = vfb->fb_address; + info.z_address = vfb->z_address; + info.format = vfb->format; + info.width = vfb->width; + info.height = vfb->height; + info.fbo = vfb->fbo; + list.push_back(info); + } + + return list; +} + +void FramebufferManagerD3D11::DestroyAllFBOs(bool forceDelete) { + draw_->BindBackbufferAsRenderTarget(); + currentRenderVfb_ = 0; + displayFramebuf_ = 0; + prevDisplayFramebuf_ = 0; + prevPrevDisplayFramebuf_ = 0; + + for (size_t i = 0; i < vfbs_.size(); ++i) { + VirtualFramebuffer *vfb = vfbs_[i]; + INFO_LOG(SCEGE, "Destroying FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format); + DestroyFramebuf(vfb); + } + vfbs_.clear(); + + for (size_t i = 0; i < bvfbs_.size(); ++i) { + VirtualFramebuffer *vfb = bvfbs_[i]; + DestroyFramebuf(vfb); + } + bvfbs_.clear(); + + for (auto it = tempFBOs_.begin(), end = tempFBOs_.end(); it != end; ++it) { + delete it->second.fbo; + } + tempFBOs_.clear(); + + DisableState(); +} + +void FramebufferManagerD3D11::FlushBeforeCopy() { + // Flush anything not yet drawn before blitting, downloading, or uploading. + // This might be a stalled list, or unflushed before a block transfer, etc. + + // TODO: It's really bad that we are calling SetRenderFramebuffer here with + // all the irrelevant state checking it'll use to decide what to do. Should + // do something more focused here. + SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); + drawEngine_->Flush(); +} + +void FramebufferManagerD3D11::Resized() { + resized_ = true; +} + +bool FramebufferManagerD3D11::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { + return false; +} + +bool FramebufferManagerD3D11::GetOutputFramebuffer(GPUDebugBuffer &buffer) { + return false; +} + +bool FramebufferManagerD3D11::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { + return false; +} + +bool FramebufferManagerD3D11::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { + return false; +} \ No newline at end of file diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 9676b47d8b..f057f99b1a 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017- PPSSPP Project. +// Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -17,4 +17,133 @@ #pragma once -class FramebufferManagerD3D11 {}; \ No newline at end of file +#include +#include +#include + +#include + +// Keeps track of allocated FBOs. +// Also provides facilities for drawing and later converting raw +// pixel data. + + +#include "Globals.h" +#include "GPU/GPUCommon.h" +#include "GPU/Common/FramebufferCommon.h" +#include "Core/Config.h" +#include "ext/native/thin3d/thin3d.h" + +class TextureCacheD3D11; +class DrawEngineD3D11; +class ShaderManagerD3D11; + +class FramebufferManagerD3D11 : public FramebufferManagerCommon { +public: + FramebufferManagerD3D11(Draw::DrawContext *draw); + ~FramebufferManagerD3D11(); + + void SetTextureCache(TextureCacheD3D11 *tc); + void SetShaderManager(ShaderManagerD3D11 *sm) { + shaderManager_ = sm; + } + void SetDrawEngine(DrawEngineD3D11 *td) { + drawEngine_ = td; + } + + virtual void DrawPixels(VirtualFramebuffer *vfb, int dstX, int dstY, const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) override; + virtual void DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, bool applyPostShader) override; + + void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, bool linearFilter); + + void DestroyAllFBOs(bool forceDelete); + + void EndFrame(); + void Resized() override; + void DeviceLost(); + void CopyDisplayToOutput(); + void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; + + void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override; + + void BindFramebufferColor(int stage, VirtualFramebuffer *framebuffer, int flags); + + void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override; + void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) override; + + std::vector GetFramebufferList(); + + virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override; + + bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes); + bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer); + bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer); + bool GetOutputFramebuffer(GPUDebugBuffer &buffer); + + virtual void RebindFramebuffer() override; + +protected: + void DisableState() override; + void ClearBuffer(bool keepState = false) override; + void FlushBeforeCopy() override; + + // Used by ReadFramebufferToMemory and later framebuffer block copies + void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override; + + bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; + void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; + +private: + void MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height); + void CompileDraw2DProgram(); + void DestroyDraw2DProgram(); + + void PackFramebufferD3D11_(VirtualFramebuffer *vfb, int x, int y, int w, int h); + void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); + + ID3D11Device *device_; + ID3D11DeviceContext *context_; + + // Used by DrawPixels + ID3D11Texture2D *drawPixelsTex_; + ID3D11ShaderResourceView *drawPixelsTexView_; + int drawPixelsTexW_; + int drawPixelsTexH_; + + ID3D11VertexShader *pFramebufferVertexShader_; + ID3D11PixelShader *pFramebufferPixelShader_; + ID3D11InputLayout *pFramebufferVertexDecl_; + + u8 *convBuf; + + int plainColorLoc_; + ID3D11PixelShader *stencilUploadPS_; + ID3D11VertexShader *stencilUploadVS_; + ID3D11InputLayout *stencilUploadInputLayout_; + bool stencilUploadFailed_; + + TextureCacheD3D11 *textureCacheD3D11_; + ShaderManagerD3D11 *shaderManager_; + DrawEngineD3D11 *drawEngine_; + + ID3D11Buffer *vbFullScreenRect_; + UINT vbFullScreenStride_ = 20; + UINT vbFullScreenOffset_ = 0; + + // Used by post-processing shader + std::vector extraFBOs_; + + bool resized_; + + struct TempFBO { + Draw::Framebuffer *fbo; + int last_frame_used; + }; + + std::map tempFBOs_; + +#if 0 + AsyncPBO *pixelBufObj_; //this isn't that large + u8 currentPBO_; +#endif +}; \ No newline at end of file diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index ebf88fedd6..5bccb87d3f 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -15,4 +15,1006 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "GPU/D3D11/GPU_D3D11.h" \ No newline at end of file +#include "GPU/D3D11/GPU_D3D11.h" + +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include + +#include "Common/ChunkFile.h" +#include "Common/GraphicsContext.h" +#include "base/NativeApp.h" +#include "base/logging.h" +#include "profiler/profiler.h" +#include "Core/Debugger/Breakpoints.h" +#include "Core/MemMapHelpers.h" +#include "Core/MIPS/MIPS.h" +#include "Core/Host.h" +#include "Core/Config.h" +#include "Core/Reporting.h" +#include "Core/System.h" + +#include "GPU/GPUState.h" +#include "GPU/ge_constants.h" +#include "GPU/GeDisasm.h" + +#include "GPU/Common/FramebufferCommon.h" +#include "GPU/D3D11/ShaderManagerD3D11.h" +#include "GPU/D3D11/GPU_D3D11.h" +#include "GPU/D3D11/FramebufferManagerD3D11.h" +#include "GPU/D3D11/DrawEngineD3D11.h" +#include "GPU/D3D11/TextureCacheD3D11.h" +#include "GPU/D3D11/D3D11Util.h" + +#include "Core/HLE/sceKernelThread.h" +#include "Core/HLE/sceKernelInterrupt.h" +#include "Core/HLE/sceGe.h" + +enum { + FLAG_FLUSHBEFORE = 1, + FLAG_FLUSHBEFOREONCHANGE = 2, + FLAG_EXECUTE = 4, // needs to actually be executed. unused for now. + FLAG_EXECUTEONCHANGE = 8, + FLAG_READS_PC = 16, + FLAG_WRITES_PC = 32, + FLAG_DIRTYONCHANGE = 64, // NOTE: Either this or FLAG_EXECUTE*, not both! +}; + +struct CommandTableEntry { + uint8_t cmd; + uint8_t flags; + uint64_t dirty; + GPU_D3D11::CmdFunc func; +}; + +static const CommandTableEntry commandTable[] = { + // Changes that dirty the framebuffer + { GE_CMD_FRAMEBUFPTR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + { GE_CMD_FRAMEBUFWIDTH, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + { GE_CMD_FRAMEBUFPIXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + { GE_CMD_ZBUFPTR, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_ZBUFWIDTH, FLAG_FLUSHBEFOREONCHANGE }, + + // Changes that dirty uniforms + { GE_CMD_FOGCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOLOR }, + { GE_CMD_FOG1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEF }, + { GE_CMD_FOG2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FOGCOEF }, + + // Should these maybe flush? + { GE_CMD_MINZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE }, + { GE_CMD_MAXZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE }, + + // Changes that dirty texture scaling. + { GE_CMD_TEXMAPMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_UVSCALEOFFSET }, + { GE_CMD_TEXSCALEU, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexScaleU }, + { GE_CMD_TEXSCALEV, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexScaleV }, + { GE_CMD_TEXOFFSETU, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexOffsetU }, + { GE_CMD_TEXOFFSETV, FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_TexOffsetV }, + + // Changes that dirty the current texture. + { GE_CMD_TEXSIZE0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_TexSize0 }, + { GE_CMD_TEXSIZE1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXSIZE2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXSIZE3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXSIZE4, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXSIZE5, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXSIZE6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXSIZE7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE }, + { GE_CMD_TEXLEVEL, 0, DIRTY_TEXTURE_PARAMS }, // Flushing on this is EXPENSIVE in Gran Turismo and of little use + { GE_CMD_TEXADDR0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE | DIRTY_UVSCALEOFFSET }, + { GE_CMD_TEXADDR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXADDR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXADDR3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXADDR4, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXADDR5, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXADDR6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXADDR7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXBUFWIDTH0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_IMAGE }, + { GE_CMD_TEXBUFWIDTH1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXBUFWIDTH2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXBUFWIDTH3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXBUFWIDTH4, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXBUFWIDTH5, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXBUFWIDTH6, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXBUFWIDTH7, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + // These must flush on change, so that LoadClut doesn't have to always flush. + { GE_CMD_CLUTADDR, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_CLUTADDRUPPER, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_CLUTFORMAT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + + // These affect the fragment shader so need flushing. + { GE_CMD_CLEARMODE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_TEXTUREMAPENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_FOGENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_TEXMODE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXSHADELS, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_SHADEMODE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_TEXFUNC, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_COLORTEST, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_ALPHATESTENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_COLORTESTENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_COLORTESTMASK, FLAG_FLUSHBEFOREONCHANGE, DIRTY_ALPHACOLORMASK }, + + // These change the vertex shader so need flushing. + { GE_CMD_REVERSENORMAL, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LIGHTINGENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LIGHTENABLE0, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LIGHTENABLE1, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LIGHTENABLE2, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LIGHTENABLE3, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LIGHTTYPE0, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LIGHTTYPE1, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LIGHTTYPE2, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LIGHTTYPE3, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_MATERIALUPDATE, FLAG_FLUSHBEFOREONCHANGE }, + + // This changes both shaders so need flushing. + { GE_CMD_LIGHTMODE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_TEXFILTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + { GE_CMD_TEXWRAP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXTURE_PARAMS }, + + // Uniform changes + { GE_CMD_ALPHATEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_ALPHACOLORREF | DIRTY_ALPHACOLORMASK }, + { GE_CMD_COLORREF, FLAG_FLUSHBEFOREONCHANGE, DIRTY_ALPHACOLORREF }, + { GE_CMD_TEXENVCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_TEXENV }, + + // Simple render state changes. Handled in StateMapping.cpp. + { GE_CMD_OFFSETX, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_OFFSETY, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_CULL, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_CULLFACEENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_DITHERENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_STENCILOP, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_STENCILTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_STENCILREPLACEVALUE }, + { GE_CMD_STENCILTESTENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_ALPHABLENDENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_BLENDMODE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_BLENDFIXEDA, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_BLENDFIXEDB, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_MASKRGB, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_MASKALPHA, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_ZTEST, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_ZTESTENABLE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_ZWRITEDISABLE, FLAG_FLUSHBEFOREONCHANGE }, + + // These can't be emulated in D3D (except a few special cases) + { GE_CMD_LOGICOP, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_LOGICOPENABLE, FLAG_FLUSHBEFOREONCHANGE }, + + // Can probably ignore this one as we don't support AA lines. + { GE_CMD_ANTIALIASENABLE, FLAG_FLUSHBEFOREONCHANGE }, + + // Morph weights. TODO: Remove precomputation? + { GE_CMD_MORPHWEIGHT0, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight }, + { GE_CMD_MORPHWEIGHT1, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight }, + { GE_CMD_MORPHWEIGHT2, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight }, + { GE_CMD_MORPHWEIGHT3, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight }, + { GE_CMD_MORPHWEIGHT4, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight }, + { GE_CMD_MORPHWEIGHT5, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight }, + { GE_CMD_MORPHWEIGHT6, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight }, + { GE_CMD_MORPHWEIGHT7, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPUCommon::Execute_MorphWeight }, + + // Control spline/bezier patches. Don't really require flushing as such, but meh. + { GE_CMD_PATCHDIVISION, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_PATCHPRIMITIVE, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_PATCHFACING, FLAG_FLUSHBEFOREONCHANGE }, + { GE_CMD_PATCHCULLENABLE, FLAG_FLUSHBEFOREONCHANGE }, + + // Viewport. + { GE_CMD_VIEWPORTXSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + { GE_CMD_VIEWPORTYSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + { GE_CMD_VIEWPORTXCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + { GE_CMD_VIEWPORTYCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + { GE_CMD_VIEWPORTZSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX }, + { GE_CMD_VIEWPORTZCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX }, + + // Region + { GE_CMD_REGION1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + { GE_CMD_REGION2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + + // Scissor + { GE_CMD_SCISSOR1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + { GE_CMD_SCISSOR2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS }, + + // Lighting base colors + { GE_CMD_AMBIENTCOLOR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_AMBIENT }, + { GE_CMD_AMBIENTALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_AMBIENT }, + { GE_CMD_MATERIALDIFFUSE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATDIFFUSE }, + { GE_CMD_MATERIALEMISSIVE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATEMISSIVE }, + { GE_CMD_MATERIALAMBIENT, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATAMBIENTALPHA }, + { GE_CMD_MATERIALALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATAMBIENTALPHA }, + { GE_CMD_MATERIALSPECULAR, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATSPECULAR }, + { GE_CMD_MATERIALSPECULARCOEF, FLAG_FLUSHBEFOREONCHANGE, DIRTY_MATSPECULAR }, + + // Light parameters + { GE_CMD_LX0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LY0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LZ0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LX1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LY1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LZ1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LX2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LY2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LZ2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LX3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + { GE_CMD_LY3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + { GE_CMD_LZ3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + + { GE_CMD_LDX0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LDY0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LDZ0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LDX1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LDY1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LDZ1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LDX2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LDY2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LDZ2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LDX3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + { GE_CMD_LDY3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + { GE_CMD_LDZ3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + + { GE_CMD_LKA0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LKB0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LKC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LKA1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LKB1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LKC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LKA2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LKB2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LKC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LKA3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + { GE_CMD_LKB3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + { GE_CMD_LKC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + + { GE_CMD_LKS0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LKS1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LKS2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LKS3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + + { GE_CMD_LKO0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LKO1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LKO2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LKO3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + + { GE_CMD_LAC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LDC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LSC0, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT0 }, + { GE_CMD_LAC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LDC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LSC1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT1 }, + { GE_CMD_LAC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LDC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LSC2, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT2 }, + { GE_CMD_LAC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + { GE_CMD_LDC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + { GE_CMD_LSC3, FLAG_FLUSHBEFOREONCHANGE, DIRTY_LIGHT3 }, + + // Ignored commands + { GE_CMD_CLIPENABLE, 0 }, + { GE_CMD_TEXFLUSH, 0 }, + { GE_CMD_TEXLODSLOPE, 0 }, + { GE_CMD_TEXSYNC, 0 }, + + // These are just nop or part of other later commands. + { GE_CMD_NOP, 0 }, + { GE_CMD_BASE, 0 }, + { GE_CMD_TRANSFERSRC, 0 }, + { GE_CMD_TRANSFERSRCW, 0 }, + { GE_CMD_TRANSFERDST, 0 }, + { GE_CMD_TRANSFERDSTW, 0 }, + { GE_CMD_TRANSFERSRCPOS, 0 }, + { GE_CMD_TRANSFERDSTPOS, 0 }, + { GE_CMD_TRANSFERSIZE, 0 }, + + // From Common. No flushing but definitely need execute. + { GE_CMD_OFFSETADDR, FLAG_EXECUTE, 0, &GPUCommon::Execute_OffsetAddr }, + { GE_CMD_ORIGIN, FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_Origin }, + { GE_CMD_PRIM, FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Prim }, + { GE_CMD_JUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_Jump }, + { GE_CMD_CALL, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_Call }, + { GE_CMD_RET, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_Ret }, + { GE_CMD_END, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_End }, + { GE_CMD_VADDR, FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Vaddr }, + { GE_CMD_IADDR, FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Iaddr }, + { GE_CMD_BJUMP, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPU_D3D11::Execute_BJump }, // EXECUTE + { GE_CMD_BOUNDINGBOX, FLAG_EXECUTE, 0, &GPU_D3D11::Execute_BoundingBox }, // + FLUSHBEFORE when we implement... or not, do we need to? + + // Changing the vertex type requires us to flush. + { GE_CMD_VERTEXTYPE, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTEONCHANGE, 0, &GPU_D3D11::Execute_VertexType }, + + { GE_CMD_BEZIER, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Bezier }, + { GE_CMD_SPLINE, FLAG_FLUSHBEFORE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_Spline }, + + // These two are actually processed in CMD_END. + { GE_CMD_SIGNAL, FLAG_FLUSHBEFORE }, + { GE_CMD_FINISH, FLAG_FLUSHBEFORE }, + + // Changes that trigger data copies. Only flushing on change for LOADCLUT must be a bit of a hack... + { GE_CMD_LOADCLUT, FLAG_FLUSHBEFOREONCHANGE | FLAG_EXECUTE, 0, &GPU_D3D11::Execute_LoadClut }, + { GE_CMD_TRANSFERSTART, FLAG_FLUSHBEFORE | FLAG_EXECUTE | FLAG_READS_PC, 0, &GPUCommon::Execute_BlockTransferStart }, + + // We don't use the dither table. + { GE_CMD_DITH0 }, + { GE_CMD_DITH1 }, + { GE_CMD_DITH2 }, + { GE_CMD_DITH3 }, + + // These handle their own flushing. + { GE_CMD_WORLDMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_WorldMtxNum }, + { GE_CMD_WORLDMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_WorldMtxData }, + { GE_CMD_VIEWMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_ViewMtxNum }, + { GE_CMD_VIEWMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_ViewMtxData }, + { GE_CMD_PROJMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_ProjMtxNum }, + { GE_CMD_PROJMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_ProjMtxData }, + { GE_CMD_TGENMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_TgenMtxNum }, + { GE_CMD_TGENMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_TgenMtxData }, + { GE_CMD_BONEMATRIXNUMBER, FLAG_EXECUTE | FLAG_READS_PC | FLAG_WRITES_PC, 0, &GPUCommon::Execute_BoneMtxNum }, + { GE_CMD_BONEMATRIXDATA, FLAG_EXECUTE, 0, &GPUCommon::Execute_BoneMtxData }, + + // Vertex Screen/Texture/Color + { GE_CMD_VSCX, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VSCY, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VSCZ, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VTCS, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VTCT, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VTCQ, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VCV, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VAP, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VFC, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_VSCV, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + + // "Missing" commands (gaps in the sequence) + { GE_CMD_UNKNOWN_03, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_0D, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_11, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_29, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_34, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_35, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_39, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_4E, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_4F, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_52, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_59, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_5A, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_B6, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_B7, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_D1, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_ED, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_EF, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_FA, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_FB, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_FC, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_FD, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + { GE_CMD_UNKNOWN_FE, FLAG_EXECUTE, 0, &GPUCommon::Execute_Unknown }, + // Appears to be debugging related or something? Hit a lot in GoW. + { GE_CMD_UNKNOWN_FF, 0 }, +}; + +GPU_D3D11::CommandInfo GPU_D3D11::cmdInfo_[256]; + +GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) + : GPUCommon(gfxCtx, draw), drawEngine_( + (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE), + (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT)) { + device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE); + context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); + lastVsync_ = g_Config.bVSync ? 1 : 0; + + stockD3D11.Create(device_); + + shaderManagerD3D11_ = new ShaderManagerD3D11(device_, context_); + framebufferManagerD3D11_ = new FramebufferManagerD3D11(draw); + framebufferManager_ = framebufferManagerD3D11_; + textureCacheD3D11_ = new TextureCacheD3D11(draw); + textureCache_ = textureCacheD3D11_; + drawEngineCommon_ = &drawEngine_; + shaderManager_ = shaderManagerD3D11_; + depalShaderCache_ = new DepalShaderCacheD3D11(device_, context_); + drawEngine_.SetShaderManager(shaderManagerD3D11_); + drawEngine_.SetTextureCache(textureCacheD3D11_); + drawEngine_.SetFramebufferManager(framebufferManagerD3D11_); + framebufferManagerD3D11_->Init(); + framebufferManagerD3D11_->SetTextureCache(textureCacheD3D11_); + framebufferManagerD3D11_->SetShaderManager(shaderManagerD3D11_); + framebufferManagerD3D11_->SetDrawEngine(&drawEngine_); + textureCacheD3D11_->SetFramebufferManager(framebufferManagerD3D11_); + textureCacheD3D11_->SetDepalShaderCache(depalShaderCache_); + textureCacheD3D11_->SetShaderManager(shaderManagerD3D11_); + + // Sanity check gstate + if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) { + ERROR_LOG(G3D, "gstate has drifted out of sync!"); + } + + // Sanity check cmdInfo_ table - no dupes please + std::set dupeCheck; + memset(cmdInfo_, 0, sizeof(cmdInfo_)); + for (size_t i = 0; i < ARRAY_SIZE(commandTable); i++) { + const u8 cmd = commandTable[i].cmd; + if (dupeCheck.find(cmd) != dupeCheck.end()) { + ERROR_LOG(G3D, "Command table Dupe: %02x (%i)", (int)cmd, (int)cmd); + } else { + dupeCheck.insert(cmd); + } + cmdInfo_[cmd].flags |= (uint64_t)commandTable[i].flags | (commandTable[i].dirty << 8); + cmdInfo_[cmd].func = commandTable[i].func; + if ((cmdInfo_[cmd].flags & (FLAG_EXECUTE | FLAG_EXECUTEONCHANGE)) && !cmdInfo_[cmd].func) { + Crash(); + } + } + // Find commands missing from the table. + for (int i = 0; i < 0xEF; i++) { + if (dupeCheck.find((u8)i) == dupeCheck.end()) { + ERROR_LOG(G3D, "Command missing from table: %02x (%i)", i, i); + } + } + + // No need to flush before the tex scale/offset commands if we are baking + // the tex scale/offset into the vertices anyway. + UpdateCmdInfo(); + + BuildReportingInfo(); + + // Some of our defaults are different from hw defaults, let's assert them. + // We restore each frame anyway, but here is convenient for tests. + textureCache_->NotifyConfigChanged(); +} + +GPU_D3D11::~GPU_D3D11() { + delete depalShaderCache_; + framebufferManagerD3D11_->DestroyAllFBOs(true); + shaderManagerD3D11_->ClearShaders(); + delete shaderManagerD3D11_; + stockD3D11.Destroy(); +} + +void GPU_D3D11::UpdateCmdInfo() { + if (g_Config.bSoftwareSkinning) { + cmdInfo_[GE_CMD_VERTEXTYPE].flags &= ~FLAG_FLUSHBEFOREONCHANGE; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_D3D11::Execute_VertexTypeSkinning; + } else { + cmdInfo_[GE_CMD_VERTEXTYPE].flags |= FLAG_FLUSHBEFOREONCHANGE; + cmdInfo_[GE_CMD_VERTEXTYPE].func = &GPU_D3D11::Execute_VertexType; + } + + CheckGPUFeatures(); +} + +void GPU_D3D11::CheckGPUFeatures() { + u32 features = 0; + + features |= GPU_SUPPORTS_BLEND_MINMAX; + features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; + features |= GPU_PREFER_CPU_DOWNLOAD; + features |= GPU_SUPPORTS_ACCURATE_DEPTH; + features |= GPU_SUPPORTS_ANISOTROPY; + features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; + + if (!g_Config.bHighQualityDepth) { + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { + // Assume we always have a 24-bit depth buffer. + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { + features |= GPU_ROUND_DEPTH_TO_16BIT; + } + + if (PSP_CoreParameter().compat.flags().ClearToRAM) { + features |= GPU_USE_CLEAR_RAM_HACK; + } + + gstate_c.featureFlags = features; +} + +// Needs to be called on GPU thread, not reporting thread. +void GPU_D3D11::BuildReportingInfo() { + using namespace Draw; + DrawContext *thin3d = gfxCtx_->GetDrawContext(); + + reportingPrimaryInfo_ = thin3d->GetInfoString(InfoField::VENDORSTRING); + reportingFullInfo_ = reportingPrimaryInfo_ + " - " + System_GetProperty(SYSPROP_GPUDRIVER_VERSION) + " - " + thin3d->GetInfoString(InfoField::SHADELANGVERSION); +} + +void GPU_D3D11::DeviceLost() { + // Simply drop all caches and textures. + // FBOs appear to survive? Or no? + shaderManagerD3D11_->ClearShaders(); + textureCacheD3D11_->Clear(false); + framebufferManagerD3D11_->DeviceLost(); +} + +void GPU_D3D11::DeviceRestore() { + // Nothing needed. +} + +void GPU_D3D11::InitClearInternal() { + bool useNonBufferedRendering = g_Config.iRenderingMode == FB_NON_BUFFERED_MODE; + if (useNonBufferedRendering) { + // device_->Clear(0, NULL, D3DCLEAR_STENCIL | D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.f, 0); + } +} + +void GPU_D3D11::DumpNextFrame() { + dumpNextFrame_ = true; +} + +void GPU_D3D11::BeginFrame() { + ScheduleEvent(GPU_EVENT_BEGIN_FRAME); +} + +void GPU_D3D11::ReapplyGfxStateInternal() { + GPUCommon::ReapplyGfxStateInternal(); + + // TODO: Dirty our caches for depth states etc +} + +void GPU_D3D11::BeginFrameInternal() { + if (resized_) { + UpdateCmdInfo(); + drawEngine_.Resized(); + textureCacheD3D11_->NotifyConfigChanged(); + resized_ = false; + } + + textureCacheD3D11_->StartFrame(); + drawEngine_.DecimateTrackedVertexArrays(); + depalShaderCache_->Decimate(); + // fragmentTestCache_.Decimate(); + + if (dumpNextFrame_) { + NOTICE_LOG(G3D, "DUMPING THIS FRAME"); + dumpThisFrame_ = true; + dumpNextFrame_ = false; + } else if (dumpThisFrame_) { + dumpThisFrame_ = false; + } + shaderManagerD3D11_->DirtyShader(); + + framebufferManagerD3D11_->BeginFrame(); +} + +void GPU_D3D11::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) { + host->GPUNotifyDisplay(framebuf, stride, format); + framebufferManagerD3D11_->SetDisplayFramebuffer(framebuf, stride, format); +} + +bool GPU_D3D11::FramebufferDirty() { + // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. + if (ThreadEnabled()) { + // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. + ScheduleEvent(GPU_EVENT_PROCESS_QUEUE); + // Allow it to process fully before deciding if it's dirty. + SyncThread(); + } + VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB(); + if (vfb) { + bool dirty = vfb->dirtyAfterDisplay; + vfb->dirtyAfterDisplay = false; + return dirty; + } + return true; +} +bool GPU_D3D11::FramebufferReallyDirty() { + // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. + if (ThreadEnabled()) { + // FIXME: Workaround for displaylists sometimes hanging unprocessed. Not yet sure of the cause. + ScheduleEvent(GPU_EVENT_PROCESS_QUEUE); + // Allow it to process fully before deciding if it's dirty. + SyncThread(); + } + + VirtualFramebuffer *vfb = framebufferManager_->GetDisplayVFB(); + if (vfb) { + bool dirty = vfb->reallyDirtyAfterDisplay; + vfb->reallyDirtyAfterDisplay = false; + return dirty; + } + return true; +} + +void GPU_D3D11::CopyDisplayToOutputInternal() { + float blendColor[4]{}; + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], blendColor, 0xFFFFFFFF); + + drawEngine_.Flush(); + + framebufferManagerD3D11_->CopyDisplayToOutput(); + framebufferManagerD3D11_->EndFrame(); + + // shaderManager_->EndFrame(); + shaderManagerD3D11_->DirtyLastShader(); + + gstate_c.Dirty(DIRTY_TEXTURE_IMAGE); +} + +// Maybe should write this in ASM... +void GPU_D3D11::FastRunLoop(DisplayList &list) { + PROFILE_THIS_SCOPE("gpuloop"); + const CommandInfo *cmdInfo = cmdInfo_; + for (; downcount > 0; --downcount) { + // We know that display list PCs have the upper nibble == 0 - no need to mask the pointer + const u32 op = *(const u32 *)(Memory::base + list.pc); + const u32 cmd = op >> 24; + const CommandInfo info = cmdInfo[cmd]; + const u8 cmdFlags = info.flags; // If we stashed the cmdFlags in the top bits of the cmdmem, we could get away with one table lookup instead of two + const u32 diff = op ^ gstate.cmdmem[cmd]; + // Inlined CheckFlushOp here to get rid of the dumpThisFrame_ check. + if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { + drawEngine_.Flush(); + } + gstate.cmdmem[cmd] = op; // TODO: no need to write if diff==0... + if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) { + (this->*info.func)(op, diff); + } else if (diff) { + uint64_t dirty = info.flags >> 8; + if (dirty) + gstate_c.Dirty(dirty); + } + list.pc += 4; + } +} + +void GPU_D3D11::FinishDeferred() { + // This finishes reading any vertex data that is pending. + drawEngine_.FinishDeferred(); +} + +inline void GPU_D3D11::CheckFlushOp(int cmd, u32 diff) { + const u8 cmdFlags = cmdInfo_[cmd].flags; + if ((cmdFlags & FLAG_FLUSHBEFORE) || (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE))) { + if (dumpThisFrame_) { + NOTICE_LOG(G3D, "================ FLUSH ================"); + } + drawEngine_.Flush(); + } +} + +void GPU_D3D11::PreExecuteOp(u32 op, u32 diff) { + CheckFlushOp(op >> 24, diff); +} + +void GPU_D3D11::ExecuteOp(u32 op, u32 diff) { + const u8 cmd = op >> 24; + const CommandInfo info = cmdInfo_[cmd]; + const u8 cmdFlags = info.flags; + if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) { + (this->*info.func)(op, diff); + } else if (diff) { + uint64_t dirty = info.flags >> 8; + if (dirty) + gstate_c.Dirty(dirty); + } +} + +void GPU_D3D11::Execute_VertexType(u32 op, u32 diff) { + if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) { + gstate_c.Dirty(DIRTY_UVSCALEOFFSET); + } +} + +void GPU_D3D11::Execute_VertexTypeSkinning(u32 op, u32 diff) { + // Don't flush when weight count changes, unless morph is enabled. + if ((diff & ~GE_VTYPE_WEIGHTCOUNT_MASK) || (op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { + // Restore and flush + gstate.vertType ^= diff; + Flush(); + gstate.vertType ^= diff; + if (diff & (GE_VTYPE_TC_MASK | GE_VTYPE_THROUGH_MASK)) + gstate_c.Dirty(DIRTY_UVSCALEOFFSET); + // In this case, we may be doing weights and morphs. + // Update any bone matrix uniforms so it uses them correctly. + if ((op & GE_VTYPE_MORPHCOUNT_MASK) != 0) { + gstate_c.Dirty(gstate_c.deferredVertTypeDirty); + gstate_c.deferredVertTypeDirty = 0; + } + } +} + +void GPU_D3D11::Execute_Prim(u32 op, u32 diff) { + SetDrawType(DRAW_PRIM); + + // This drives all drawing. All other state we just buffer up, then we apply it only + // when it's time to draw. As most PSP games set state redundantly ALL THE TIME, this is a huge optimization. + + u32 data = op & 0xFFFFFF; + u32 count = data & 0xFFFF; + // Upper bits are ignored. + GEPrimitiveType prim = static_cast((data >> 16) & 7); + + if (count == 0) + return; + + // Discard AA lines as we can't do anything that makes sense with these anyway. The SW plugin might, though. + + if (gstate.isAntiAliasEnabled()) { + // Discard AA lines in DOA + if (prim == GE_PRIM_LINE_STRIP) + return; + // Discard AA lines in Summon Night 5 + if ((prim == GE_PRIM_LINES) && gstate.isSkinningEnabled()) + return; + } + + // This also make skipping drawing very effective. + framebufferManagerD3D11_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); + if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { + drawEngine_.SetupVertexDecoder(gstate.vertType); + // Rough estimate, not sure what's correct. + cyclesExecuted += EstimatePerVertexCost() * count; + return; + } + + u32 vertexAddr = gstate_c.vertexAddr; + if (!Memory::IsValidAddress(vertexAddr)) { + ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", vertexAddr); + return; + } + + void *verts = Memory::GetPointerUnchecked(vertexAddr); + void *inds = 0; + u32 vertexType = gstate.vertType; + if ((vertexType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { + u32 indexAddr = gstate_c.indexAddr; + if (!Memory::IsValidAddress(indexAddr)) { + ERROR_LOG_REPORT(G3D, "Bad index address %08x!", indexAddr); + return; + } + inds = Memory::GetPointerUnchecked(indexAddr); + } + +#ifndef MOBILE_DEVICE + if (prim > GE_PRIM_RECTANGLES) { + ERROR_LOG_REPORT_ONCE(reportPrim, G3D, "Unexpected prim type: %d", prim); + } +#endif + + int bytesRead = 0; + drawEngine_.SubmitPrim(verts, inds, prim, count, vertexType, &bytesRead); + + int vertexCost = EstimatePerVertexCost() * count; + gpuStats.vertexGPUCycles += vertexCost; + cyclesExecuted += vertexCost; + + // After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed). + // Some games rely on this, they don't bother reloading VADDR and IADDR. + // The VADDR/IADDR registers are NOT updated. + AdvanceVerts(vertexType, count, bytesRead); +} + +void GPU_D3D11::Execute_Bezier(u32 op, u32 diff) { + SetDrawType(DRAW_BEZIER); + + // This also make skipping drawing very effective. + framebufferManagerD3D11_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); + if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { + // TODO: Should this eat some cycles? Probably yes. Not sure if important. + return; + } + + if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { + ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + return; + } + + void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); + void *indices = NULL; + if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { + if (!Memory::IsValidAddress(gstate_c.indexAddr)) { + ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); + return; + } + indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); + } + + if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { + DEBUG_LOG_REPORT(G3D, "Bezier + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); + } + if (vertTypeIsSkinningEnabled(gstate.vertType)) { + DEBUG_LOG_REPORT(G3D, "Bezier + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); + } + + GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); + int bz_ucount = op & 0xFF; + int bz_vcount = (op >> 8) & 0xFF; + bool computeNormals = gstate.isLightingEnabled(); + bool patchFacing = gstate.patchfacing & 1; + int bytesRead = 0; + drawEngine_.SubmitBezier(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), bz_ucount, bz_vcount, patchPrim, computeNormals, patchFacing, gstate.vertType, &bytesRead); + + // After drawing, we advance pointers - see SubmitPrim which does the same. + int count = bz_ucount * bz_vcount; + AdvanceVerts(gstate.vertType, count, bytesRead); +} + +void GPU_D3D11::Execute_Spline(u32 op, u32 diff) { + SetDrawType(DRAW_SPLINE); + + // This also make skipping drawing very effective. + framebufferManagerD3D11_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason); + if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) { + // TODO: Should this eat some cycles? Probably yes. Not sure if important. + return; + } + + if (!Memory::IsValidAddress(gstate_c.vertexAddr)) { + ERROR_LOG_REPORT(G3D, "Bad vertex address %08x!", gstate_c.vertexAddr); + return; + } + + void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); + void *indices = NULL; + if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { + if (!Memory::IsValidAddress(gstate_c.indexAddr)) { + ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr); + return; + } + indices = Memory::GetPointerUnchecked(gstate_c.indexAddr); + } + + if (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) { + DEBUG_LOG_REPORT(G3D, "Spline + morph: %i", (gstate.vertType & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT); + } + if (vertTypeIsSkinningEnabled(gstate.vertType)) { + DEBUG_LOG_REPORT(G3D, "Spline + skinning: %i", vertTypeGetNumBoneWeights(gstate.vertType)); + } + + int sp_ucount = op & 0xFF; + int sp_vcount = (op >> 8) & 0xFF; + int sp_utype = (op >> 16) & 0x3; + int sp_vtype = (op >> 18) & 0x3; + GEPatchPrimType patchPrim = gstate.getPatchPrimitiveType(); + bool computeNormals = gstate.isLightingEnabled(); + bool patchFacing = gstate.patchfacing & 1; + u32 vertType = gstate.vertType; + int bytesRead = 0; + drawEngine_.SubmitSpline(control_points, indices, gstate.getPatchDivisionU(), gstate.getPatchDivisionV(), sp_ucount, sp_vcount, sp_utype, sp_vtype, patchPrim, computeNormals, patchFacing, vertType, &bytesRead); + + // After drawing, we advance pointers - see SubmitPrim which does the same. + int count = sp_ucount * sp_vcount; + AdvanceVerts(gstate.vertType, count, bytesRead); +} + +void GPU_D3D11::Execute_TexSize0(u32 op, u32 diff) { + // Render to texture may have overridden the width/height. + // Don't reset it unless the size is different / the texture has changed. + if (diff || gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS)) { + gstate_c.curTextureWidth = gstate.getTextureWidth(0); + gstate_c.curTextureHeight = gstate.getTextureHeight(0); + gstate_c.Dirty(DIRTY_UVSCALEOFFSET); + // We will need to reset the texture now. + gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); + } +} + +void GPU_D3D11::Execute_LoadClut(u32 op, u32 diff) { + gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); + textureCacheD3D11_->LoadClut(gstate.getClutAddress(), gstate.getClutLoadBytes()); + // This could be used to "dirty" textures with clut. +} + +void GPU_D3D11::GetStats(char *buffer, size_t bufsize) { + float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f; + snprintf(buffer, bufsize - 1, + "DL processing time: %0.2f ms\n" + "Draw calls: %i, flushes %i\n" + "Cached Draw calls: %i\n" + "Num Tracked Vertex Arrays: %i\n" + "GPU cycles executed: %d (%f per vertex)\n" + "Commands per call level: %i %i %i %i\n" + "Vertices submitted: %i\n" + "Cached, Uncached Vertices Drawn: %i, %i\n" + "FBOs active: %i\n" + "Textures active: %i, decoded: %i invalidated: %i\n" + "Vertex, Fragment shaders loaded: %i, %i\n", + gpuStats.msProcessingDisplayLists * 1000.0f, + gpuStats.numDrawCalls, + gpuStats.numFlushes, + gpuStats.numCachedDrawCalls, + gpuStats.numTrackedVertexArrays, + gpuStats.vertexGPUCycles + gpuStats.otherGPUCycles, + vertexAverageCycles, + gpuStats.gpuCommandsAtCallLevel[0], gpuStats.gpuCommandsAtCallLevel[1], gpuStats.gpuCommandsAtCallLevel[2], gpuStats.gpuCommandsAtCallLevel[3], + gpuStats.numVertsSubmitted, + gpuStats.numCachedVertsDrawn, + gpuStats.numUncachedVertsDrawn, + (int)framebufferManagerD3D11_->NumVFBs(), + (int)textureCacheD3D11_->NumLoadedTextures(), + gpuStats.numTexturesDecoded, + gpuStats.numTextureInvalidations, + shaderManagerD3D11_->GetNumVertexShaders(), + shaderManagerD3D11_->GetNumFragmentShaders() + ); +} + +void GPU_D3D11::ClearCacheNextFrame() { + textureCacheD3D11_->ClearNextFrame(); +} + +void GPU_D3D11::ClearShaderCache() { + shaderManagerD3D11_->ClearShaders(); +} + +std::vector GPU_D3D11::GetFramebufferList() { + return framebufferManagerD3D11_->GetFramebufferList(); +} + +void GPU_D3D11::DoState(PointerWrap &p) { + GPUCommon::DoState(p); + + // TODO: Some of these things may not be necessary. + // None of these are necessary when saving. + if (p.mode == p.MODE_READ) { + textureCacheD3D11_->Clear(true); + drawEngine_.ClearTrackedVertexArrays(); + + gstate_c.Dirty(DIRTY_TEXTURE_IMAGE); + framebufferManagerD3D11_->DestroyAllFBOs(true); + shaderManagerD3D11_->ClearShaders(); + } +} + +bool GPU_D3D11::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { + return framebufferManagerD3D11_->GetCurrentFramebuffer(buffer, type, maxRes); +} + +bool GPU_D3D11::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { + return framebufferManagerD3D11_->GetCurrentDepthbuffer(buffer); +} + +bool GPU_D3D11::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { + return framebufferManagerD3D11_->GetCurrentStencilbuffer(buffer); +} + +bool GPU_D3D11::GetCurrentTexture(GPUDebugBuffer &buffer, int level) { + if (!gstate.isTextureMapEnabled()) { + return false; + } + + // TODO: Implement! + + return false; +} + +bool GPU_D3D11::GetCurrentClut(GPUDebugBuffer &buffer) { + return textureCacheD3D11_->GetCurrentClutBuffer(buffer); +} + +bool GPU_D3D11::GetOutputFramebuffer(GPUDebugBuffer &buffer) { + return framebufferManagerD3D11_->GetOutputFramebuffer(buffer); +} + +bool GPU_D3D11::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) { + return drawEngine_.GetCurrentSimpleVertices(count, vertices, indices); +} + +std::vector GPU_D3D11::DebugGetShaderIDs(DebugShaderType type) { + if (type == SHADER_TYPE_VERTEXLOADER) { + return drawEngine_.DebugGetVertexLoaderIDs(); + } else { + return shaderManagerD3D11_->DebugGetShaderIDs(type); + } +} + +std::string GPU_D3D11::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) { + if (type == SHADER_TYPE_VERTEXLOADER) { + return drawEngine_.DebugGetVertexLoaderString(id, stringType); + } else { + return shaderManagerD3D11_->DebugGetShaderString(id, type, stringType); + } +} diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index 79ec63a29e..337342f9c7 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -28,105 +28,99 @@ #include "GPU/D3D11/DepalettizeShaderD3D11.h" #include "GPU/Common/VertexDecoderCommon.h" -namespace D3D11 { +class ShaderManagerD3D11; +class LinkedShaderD3D11; - class ShaderManagerD3D11; - class LinkedShaderD3D11; +class GPU_D3D11 : public GPUCommon { +public: + GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw); + ~GPU_D3D11(); - class GPU_D3D11 : public GPUCommon { - public: - GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw); - ~GPU_D3D11(); + void CheckGPUFeatures(); + void PreExecuteOp(u32 op, u32 diff) override; + void ExecuteOp(u32 op, u32 diff) override; - void CheckGPUFeatures(); - void PreExecuteOp(u32 op, u32 diff) override; - void ExecuteOp(u32 op, u32 diff) override; + void ReapplyGfxStateInternal() override; + void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override; + void BeginFrame() override; + void GetStats(char *buffer, size_t bufsize) override; + void ClearCacheNextFrame() override; + void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. + void DeviceRestore() override; - void ReapplyGfxStateInternal() override; - void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override; - void BeginFrame() override; - void GetStats(char *buffer, size_t bufsize) override; - void ClearCacheNextFrame() override; - void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. - void DeviceRestore() override; + void DumpNextFrame() override; + void DoState(PointerWrap &p) override; - void DumpNextFrame() override; - void DoState(PointerWrap &p) override; + void ClearShaderCache() override; + bool DecodeTexture(u8 *dest, const GPUgstate &state) override { + return false; + } + bool FramebufferDirty() override; + bool FramebufferReallyDirty() override; - void ClearShaderCache() override; - bool DecodeTexture(u8 *dest, const GPUgstate &state) override { - return false; - } - bool FramebufferDirty() override; - bool FramebufferReallyDirty() override; + void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override { + primaryInfo = reportingPrimaryInfo_; + fullInfo = reportingFullInfo_; + } + std::vector GetFramebufferList() override; - void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override { - primaryInfo = reportingPrimaryInfo_; - fullInfo = reportingFullInfo_; - } - std::vector GetFramebufferList() override; + bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes = -1) override; + bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override; + bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override; + bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override; + bool GetCurrentClut(GPUDebugBuffer &buffer) override; + bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; + bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) override; - bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes = -1) override; - bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override; - bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override; - bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override; - bool GetCurrentClut(GPUDebugBuffer &buffer) override; - bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; - bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) override; - - typedef void (GPU_D3D11::*CmdFunc)(u32 op, u32 diff); - struct CommandInfo { - uint64_t flags; - GPU_D3D11::CmdFunc func; - }; - - void Execute_Prim(u32 op, u32 diff); - void Execute_Bezier(u32 op, u32 diff); - void Execute_Spline(u32 op, u32 diff); - void Execute_VertexType(u32 op, u32 diff); - void Execute_VertexTypeSkinning(u32 op, u32 diff); - void Execute_TexSize0(u32 op, u32 diff); - void Execute_LoadClut(u32 op, u32 diff); - - // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. - std::vector DebugGetShaderIDs(DebugShaderType shader) override; - std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; - - protected: - void FastRunLoop(DisplayList &list) override; - void FinishDeferred() override; - - private: - void UpdateCmdInfo(); - - void Flush() { - drawEngine_.Flush(); - } - // void ApplyDrawState(int prim); - void CheckFlushOp(int cmd, u32 diff); - void BuildReportingInfo(); - - void InitClearInternal() override; - void BeginFrameInternal() override; - void CopyDisplayToOutputInternal() override; - - ID3D11Device *device_; - ID3D11DeviceContext *context_; - - FramebufferManagerD3D11 *framebufferManagerD3D11_; - TextureCacheD3D11 *textureCacheD3D11_; - DepalShaderCacheD3D11 depalShaderCache_; - DrawEngineD3D11 drawEngine_; - ShaderManagerD3D11 *shaderManagerD3D11_; - - static CommandInfo cmdInfo_[256]; - - int lastVsync_; - - std::string reportingPrimaryInfo_; - std::string reportingFullInfo_; + typedef void (GPU_D3D11::*CmdFunc)(u32 op, u32 diff); + struct CommandInfo { + uint64_t flags; + GPU_D3D11::CmdFunc func; }; -} // namespace D3D11 + void Execute_Prim(u32 op, u32 diff); + void Execute_Bezier(u32 op, u32 diff); + void Execute_Spline(u32 op, u32 diff); + void Execute_VertexType(u32 op, u32 diff); + void Execute_VertexTypeSkinning(u32 op, u32 diff); + void Execute_TexSize0(u32 op, u32 diff); + void Execute_LoadClut(u32 op, u32 diff); -typedef D3D11::GPU_D3D11 D3D11_GPU; + // Using string because it's generic - makes no assumptions on the size of the shader IDs of this backend. + std::vector DebugGetShaderIDs(DebugShaderType shader) override; + std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; + +protected: + void FastRunLoop(DisplayList &list) override; + void FinishDeferred() override; + +private: + void UpdateCmdInfo(); + + void Flush() { + drawEngine_.Flush(); + } + // void ApplyDrawState(int prim); + void CheckFlushOp(int cmd, u32 diff); + void BuildReportingInfo(); + + void InitClearInternal() override; + void BeginFrameInternal() override; + void CopyDisplayToOutputInternal() override; + + ID3D11Device *device_; + ID3D11DeviceContext *context_; + + FramebufferManagerD3D11 *framebufferManagerD3D11_; + TextureCacheD3D11 *textureCacheD3D11_; + DepalShaderCacheD3D11 *depalShaderCache_; + DrawEngineD3D11 drawEngine_; + ShaderManagerD3D11 *shaderManagerD3D11_; + + static CommandInfo cmdInfo_[256]; + + int lastVsync_; + + std::string reportingPrimaryInfo_; + std::string reportingFullInfo_; +}; \ No newline at end of file diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index aad5b924bf..25d45f6ea8 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -39,25 +39,19 @@ #include "GPU/D3D11/ShaderManagerD3D11.h" #include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" #include "GPU/D3D11/VertexShaderGeneratorD3D11.h" +#include "GPU/D3D11/D3D11Util.h" D3D11FragmentShader::D3D11FragmentShader(ID3D11Device *device, ShaderID id, const char *code, bool useHWTransform) : device_(device), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(0) { source_ = code; - std::string errorMessage; - #ifdef SHADERLOG OutputDebugStringA(code); #endif - uint8_t *bytecode; - UINT bytecodeSize; - - HRESULT hr = device_->CreatePixelShader(bytecode, bytecodeSize, nullptr, &module_); - if (FAILED(hr)) { + module_ = CreatePixelShaderD3D11(device, code, strlen(code)); + if (!module_) failed_ = true; - return; - } } D3D11FragmentShader::~D3D11FragmentShader() { @@ -79,19 +73,14 @@ std::string D3D11FragmentShader::GetShaderString(DebugShaderStringType type) con D3D11VertexShader::D3D11VertexShader(ID3D11Device *device, ShaderID id, const char *code, int vertType, bool useHWTransform, bool usesLighting) : device_(device), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(nullptr), usesLighting_(usesLighting) { source_ = code; - std::string errorMessage; - std::vector spirv; + #ifdef SHADERLOG OutputDebugStringA(code); #endif - uint8_t *bytecode; - UINT bytecodeSize; - HRESULT hr = device_->CreateVertexShader(bytecode, bytecodeSize, nullptr, &module_); - if (FAILED(hr)) { + module_ = CreateVertexShaderD3D11(device, code, strlen(code), &bytecode_); + if (!module_) failed_ = true; - return; - } } D3D11VertexShader::~D3D11VertexShader() { @@ -120,6 +109,13 @@ ShaderManagerD3D11::ShaderManagerD3D11(ID3D11Device *device, ID3D11DeviceContext ILOG("sizeof(ub_base): %d", (int)sizeof(ub_base)); ILOG("sizeof(ub_lights): %d", (int)sizeof(ub_lights)); ILOG("sizeof(ub_bones): %d", (int)sizeof(ub_bones)); + + D3D11_BUFFER_DESC desc{sizeof(ub_base), D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE }; + device_->CreateBuffer(&desc, nullptr, &push_base); + desc.ByteWidth = sizeof(ub_lights); + device_->CreateBuffer(&desc, nullptr, &push_lights); + desc.ByteWidth = sizeof(ub_bones); + device_->CreateBuffer(&desc, nullptr, &push_bones); } ShaderManagerD3D11::~ShaderManagerD3D11() { @@ -162,12 +158,25 @@ void ShaderManagerD3D11::DirtyLastShader() { // disables vertex arrays uint64_t ShaderManagerD3D11::UpdateUniforms() { uint64_t dirty = gstate_c.GetDirtyUniforms(); if (dirty != 0) { - if (dirty & DIRTY_BASE_UNIFORMS) + D3D11_MAPPED_SUBRESOURCE map; + if (dirty & DIRTY_BASE_UNIFORMS) { BaseUpdateUniforms(&ub_base, dirty); - if (dirty & DIRTY_LIGHT_UNIFORMS) + context_->Map(push_base, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &ub_base, sizeof(ub_base)); + context_->Unmap(push_base, 0); + } + if (dirty & DIRTY_LIGHT_UNIFORMS) { LightUpdateUniforms(&ub_lights, dirty); - if (dirty & DIRTY_BONE_UNIFORMS) + context_->Map(push_lights, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &ub_lights, sizeof(ub_lights)); + context_->Unmap(push_lights, 0); + } + if (dirty & DIRTY_BONE_UNIFORMS) { BoneUpdateUniforms(&ub_bones, dirty); + context_->Map(push_bones, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &ub_bones, sizeof(ub_bones)); + context_->Unmap(push_bones, 0); + } } gstate_c.CleanUniforms(); return dirty; diff --git a/GPU/D3D11/ShaderManagerD3D11.h b/GPU/D3D11/ShaderManagerD3D11.h index 52ebdc4547..b7cbbbe24c 100644 --- a/GPU/D3D11/ShaderManagerD3D11.h +++ b/GPU/D3D11/ShaderManagerD3D11.h @@ -62,7 +62,7 @@ public: ~D3D11VertexShader(); const std::string &source() const { return source_; } - + const std::vector &bytecode() const { return bytecode_; } bool Failed() const { return failed_; } bool UseHWTransform() const { return useHWTransform_; } bool HasBones() const { @@ -80,6 +80,8 @@ protected: ID3D11Device *device_; std::string source_; + std::vector bytecode_; + bool failed_; bool useHWTransform_; bool usesLighting_; @@ -137,6 +139,11 @@ private: UB_VS_Lights ub_lights; UB_VS_Bones ub_bones; + // Not actual pushbuffers, requires D3D11.1, let's try to live without that first. + ID3D11Buffer *push_base; + ID3D11Buffer *push_lights; + ID3D11Buffer *push_bones; + D3D11FragmentShader *lastFShader_; D3D11VertexShader *lastVShader_; diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 94fad0f300..fa3693a5aa 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -17,6 +17,8 @@ #include +#include "math/dataconv.h" + #include "GPU/Math3D.h" #include "GPU/GPUState.h" #include "GPU/ge_constants.h" @@ -26,6 +28,8 @@ #include "Core/Reporting.h" #include "GPU/Common/FramebufferCommon.h" +#include "GPU/D3D11/DrawEngineD3D11.h" +#include "GPU/D3D11/FramebufferManagerD3D11.h" // These tables all fit into u8s. static const D3D11_BLEND d3d11BlendFactorLookup[(size_t)BlendFactor::COUNT] = { @@ -377,3 +381,60 @@ void ConvertStateToKeys(FramebufferManagerCommon *fbManager, ShaderManagerD3D11 gstate_c.Dirty(DIRTY_DEPTHRANGE); } } + +void DrawEngineD3D11::ApplyDrawState(int prim) { + D3D11StateKeys keys; + D3D11DynamicState dynState; + ConvertStateToKeys(framebufferManager_, shaderManager_, prim, keys, dynState); + + uint32_t blendKey, depthKey, rasterKey; + 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; + ID3D11RasterizerState *rs = nullptr; + + auto blendIter = blendCache_.find(blendKey); + if (blendIter == blendCache_.end()) { + D3D11_BLEND_DESC desc{}; + D3D11_RENDER_TARGET_BLEND_DESC &rt = desc.RenderTarget[0]; + 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; + } + + auto depthIter = depthStencilCache_.find(depthKey); + if (depthIter == depthStencilCache_.end()) { + D3D11_DEPTH_STENCIL_DESC desc{}; + desc.DepthEnable = keys.depthStencil.depthTestEnable; + desc.DepthWriteMask = keys.depthStencil.depthWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + desc.StencilEnable = keys.depthStencil.stencilTestEnable; + // ... + device_->CreateDepthStencilState(&desc, &ds); + depthStencilCache_.insert(std::pair(depthKey, ds)); + } else { + ds = depthIter->second; + } + + float blendColor[4]; + Uint8x4ToFloat4(blendColor, dynState.blendColor); + context_->OMSetBlendState(bs, blendColor, 0xFFFFFFFF); +} + +void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef) { + if (applyStencilRef) { + ID3D11DepthStencilState *state; + context_->OMSetDepthStencilState(state, stencilRef); + } +} \ No newline at end of file diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp new file mode 100644 index 0000000000..a674b36494 --- /dev/null +++ b/GPU/D3D11/StencilBufferD3D11.cpp @@ -0,0 +1,261 @@ +// Copyright (c) 2014- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include + +#include "base/logging.h" + +#include "gfx/d3d9_state.h" +#include "ext/native/thin3d/thin3d.h" +#include "Core/Reporting.h" +#include "GPU/D3D11/FramebufferManagerD3D11.h" +#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" +#include "GPU/D3D11/ShaderManagerD3D11.h" +#include "GPU/D3D11/TextureCacheD3D11.h" +#include "GPU/D3D11/D3D11Util.h" + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +struct StencilUB { + float u_stencilValue[4]; +}; + +static const char *stencil_ps = +"sampler tex: register(s0);\n" +"cbuffer base : register(b0) {\n" +" float4 u_stencilValue;\n" +"};\n" +"struct PS_IN {\n" +" float2 v_texcoord0 : TEXCOORD0;\n" +"};\n" +"float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n" +"float4 main(PS_IN In) : COLOR {\n" +" float4 index = tex2D(tex, In.v_texcoord0);\n" +" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue.x);\n" +" clip(fmod(floor(shifted), 2.0) - 0.99);\n" +" return index.aaaa;\n" +"}\n"; + +static const char *stencil_vs = +"struct VS_IN {\n" +" float4 a_position : POSITION;\n" +" float2 a_texcoord0 : TEXCOORD0;\n" +"};\n" +"struct VS_OUT {\n" +" float4 position : POSITION;\n" +" float2 v_texcoord0 : TEXCOORD0;\n" +"};\n" +"VS_OUT main(VS_IN In) {\n" +" VS_OUT Out;\n" +" Out.position = In.a_position;\n" +" Out.v_texcoord0 = In.a_texcoord0;\n" +" return Out;\n" +"}\n"; + +static u8 StencilBits5551(const u8 *ptr8, u32 numPixels) { + const u32 *ptr = (const u32 *)ptr8; + + for (u32 i = 0; i < numPixels / 2; ++i) { + if (ptr[i] & 0x80008000) { + return 1; + } + } + return 0; +} + +static u8 StencilBits4444(const u8 *ptr8, u32 numPixels) { + const u32 *ptr = (const u32 *)ptr8; + u32 bits = 0; + + for (u32 i = 0; i < numPixels / 2; ++i) { + bits |= ptr[i]; + } + + return ((bits >> 12) & 0xF) | (bits >> 28); +} + +static u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { + const u32 *ptr = (const u32 *)ptr8; + u32 bits = 0; + + for (u32 i = 0; i < numPixels; ++i) { + bits |= ptr[i]; + } + + return bits >> 24; +} + +// TODO : If SV_StencilRef is available (D3D11.3) then this can be done in a single pass. +bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZero) { + if (!MayIntersectFramebuffer(addr)) { + return false; + } + + VirtualFramebuffer *dstBuffer = 0; + for (size_t i = 0; i < vfbs_.size(); ++i) { + VirtualFramebuffer *vfb = vfbs_[i]; + if (MaskedEqual(vfb->fb_address, addr)) { + dstBuffer = vfb; + } + } + if (!dstBuffer) { + return false; + } + + int values = 0; + u8 usedBits = 0; + + const u8 *src = Memory::GetPointer(addr); + if (!src) { + return false; + } + + switch (dstBuffer->format) { + case GE_FORMAT_565: + // Well, this doesn't make much sense. + return false; + case GE_FORMAT_5551: + usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 2; + break; + case GE_FORMAT_4444: + usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 16; + break; + case GE_FORMAT_8888: + usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 256; + break; + case GE_FORMAT_INVALID: + // Impossible. + break; + } + + if (usedBits == 0) { + if (skipZero) { + // Common when creating buffers, it's already 0. We're done. + return false; + } + + /* + // TODO: Find a fast way to clear stencil+alpha. Probably a quad. + // Let's not bother with the shader if it's just zero. + dxstate.scissorTest.disable(); + dxstate.colorMask.set(false, false, false, true); + // TODO: Verify this clears only stencil/alpha. + pD3Ddevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0, 0, 0, 0), 0.0f, 0); + */ + return true; + } + + if (stencilUploadFailed_) { + return false; + } + + // TODO: Helper with logging? + if (!stencilUploadPS_) { + std::string errorMessage; + stencilUploadPS_ = CreatePixelShaderD3D11(device_, stencil_ps, strlen(stencil_ps)); + } + if (!stencilUploadVS_) { + std::string errorMessage; + std::vector byteCode; + stencilUploadVS_ = CreateVertexShaderD3D11(device_, stencil_vs, strlen(stencil_vs), &byteCode); + // stencilUploadInputLayout_ = device_->CreateInputLayout() + } + if (!stencilUploadPS_ || !stencilUploadVS_) { + stencilUploadFailed_ = true; + return false; + } + + shaderManager_->DirtyLastShader(); + + DisableState(); + + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF); + context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); + context_->RSSetState(stockD3D11.rasterStateNoCull); + + u16 w = dstBuffer->renderWidth; + u16 h = dstBuffer->renderHeight; + + if (dstBuffer->fbo) { + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo); + } + D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }; + context_->RSSetViewports(1, &vp); + + MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight); + + // Zero stencil + draw_->Clear(Draw::ClearFlag::STENCIL, 0, 0, 0); + + float fw = dstBuffer->width; + float fh = dstBuffer->height; + + float coord[20] = { + 0.0f,0.0f,0.0f, 0.0f,0.0f, + fw,0.0f,0.0f, 1.0f,0.0f, + fw,fh,0.0f, 1.0f,1.0f, + 0.0f,fh,0.0f, 0.0f,1.0f, + }; + // I think all these calculations pretty much cancel out? + float invDestW = 1.0f / (fw * 0.5f); + float invDestH = 1.0f / (fh * 0.5f); + for (int i = 0; i < 4; i++) { + coord[i * 5] = coord[i * 5] * invDestW - 1.0f; + coord[i * 5 + 1] = -(coord[i * 5 + 1] * invDestH - 1.0f); + } + + /* TODO + // context_->IASetInputLayout(ia); + context_->PSSetShader(stencilUploadPS_); + context_->VSSetSamplers(stencilUploadVS_); + context_->pD3Ddevice->SetTexture(0, drawPixelsTex_); + + shaderManager_->DirtyLastShader(); + textureCacheD3D11_->ForgetLastTexture(); + + for (int i = 1; i < values; i += i) { + if (!(usedBits & i)) { + // It's already zero, let's skip it. + continue; + } + if (dstBuffer->format == GE_FORMAT_4444) { + dxstate.stencilMask.set(i | (i << 4)); + const float f[4] = {i * (16.0f / 255.0f)}; + pD3Ddevice->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); + } else if (dstBuffer->format == GE_FORMAT_5551) { + dxstate.stencilMask.set(0xFF); + const float f[4] = {i * (128.0f / 255.0f)}; + pD3Ddevice->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); + } else { + dxstate.stencilMask.set(i); + const float f[4] = {i * (1.0f / 255.0f)}; + pD3Ddevice->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); + } + HRESULT hr = pD3Ddevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coord, 5 * sizeof(float)); + if (FAILED(hr)) { + ERROR_LOG_REPORT(G3D, "Failed to draw stencil bit %x: %08x", i, hr); + } + } + dxstate.stencilMask.set(0xFF); + RebindFramebuffer(); + */ + return true; +} diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index e69de29bb2..fe54b64039 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -0,0 +1,1200 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include +#include +#include + +#include + +#include "Core/MemMap.h" +#include "Core/Reporting.h" +#include "GPU/ge_constants.h" +#include "GPU/GPUState.h" +#include "GPU/D3D11/FragmentShaderGeneratorD3D11.h" +#include "GPU/D3D11/TextureCacheD3D11.h" +#include "GPU/D3D11/FramebufferManagerD3D11.h" +#include "GPU/D3D11/ShaderManagerD3D11.h" +#include "GPU/D3D11/DepalettizeShaderD3D11.h" +#include "GPU/D3D11/D3D11Util.h" +#include "GPU/Common/FramebufferCommon.h" +#include "GPU/Common/TextureDecoder.h" +#include "Core/Config.h" +#include "Core/Host.h" + +#include "ext/xxhash.h" +#include "math/math_util.h" + + +#define INVALID_TEX (ID3D11ShaderResourceView *)(-1LL) + + // If a texture hasn't been seen for this many frames, get rid of it. +#define TEXTURE_KILL_AGE 200 +#define TEXTURE_KILL_AGE_LOWMEM 60 + // Not used in lowmem mode. +#define TEXTURE_SECOND_KILL_AGE 100 + + // Try to be prime to other decimation intervals. +#define TEXCACHE_DECIMATION_INTERVAL 13 + +#define TEXCACHE_MAX_TEXELS_SCALED (256*256) // Per frame + +#define TEXCACHE_MIN_PRESSURE 16 * 1024 * 1024 // Total in VRAM +#define TEXCACHE_SECOND_MIN_PRESSURE 4 * 1024 * 1024 + +static const D3D11_INPUT_ELEMENT_DESC g_FramebufferVertexElements[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12,}, +}; + +SamplerCacheD3D11::~SamplerCacheD3D11() { + for (auto &iter : cache_) { + iter.second->Release(); + } +} + +ID3D11SamplerState *SamplerCacheD3D11::GetOrCreateSampler(ID3D11Device *device, const SamplerCacheKey &key) { + auto iter = cache_.find(key); + if (iter != cache_.end()) { + return iter->second; + } + + D3D11_SAMPLER_DESC samp{}; + samp.AddressU = key.sClamp ? D3D11_TEXTURE_ADDRESS_CLAMP : D3D11_TEXTURE_ADDRESS_WRAP; + samp.AddressV = key.tClamp ? D3D11_TEXTURE_ADDRESS_CLAMP : D3D11_TEXTURE_ADDRESS_WRAP; + samp.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + if (gstate_c.Supports(GPU_SUPPORTS_ANISOTROPY) && g_Config.iAnisotropyLevel > 0) { + samp.MaxAnisotropy = (float)(1 << g_Config.iAnisotropyLevel); + } else { + samp.MaxAnisotropy = 1.0f; + } + int filterKey = ((int)key.minFilt << 2) | ((int)key.magFilt << 1) | ((int)key.mipFilt); + static const D3D11_FILTER filters[8] = { + D3D11_FILTER_MIN_MAG_MIP_POINT, + D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR, + D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT, + D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR, + D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT, + D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, + D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT, + D3D11_FILTER_MIN_MAG_MIP_LINEAR, + }; + samp.Filter = filters[filterKey]; + samp.MaxLOD = key.maxLevel; + samp.MinLOD = 0.0f; + samp.MipLODBias = 0.0f; + + ID3D11SamplerState *sampler; + device->CreateSamplerState(&samp, &sampler); + cache_[key] = sampler; + return sampler; +} + +TextureCacheD3D11::TextureCacheD3D11(Draw::DrawContext *draw) + : TextureCacheCommon(draw) { + lastBoundTexture = INVALID_TEX; + decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL; + + HRESULT result = 0; + + maxAnisotropyLevel = 16; + SetupTextureDecoder(); + + nextTexture_ = nullptr; +} + +TextureCacheD3D11::~TextureCacheD3D11() { + // pFramebufferVertexDecl->Release(); + Clear(true); +} + +void TextureCacheD3D11::SetFramebufferManager(FramebufferManagerD3D11 *fbManager) { + framebufferManagerD3D11_ = fbManager; + framebufferManager_ = fbManager; +} + +void TextureCacheD3D11::Clear(bool delete_them) { + context_->PSSetShaderResources(0, 1, nullptr); + lastBoundTexture = INVALID_TEX; + if (delete_them) { + for (TexCache::iterator iter = cache.begin(); iter != cache.end(); ++iter) { + DEBUG_LOG(G3D, "Deleting texture %p", iter->second.texturePtr); + ReleaseTexture(&iter->second); + } + for (TexCache::iterator iter = secondCache.begin(); iter != secondCache.end(); ++iter) { + DEBUG_LOG(G3D, "Deleting texture %p", iter->second.texturePtr); + ReleaseTexture(&iter->second); + } + } + if (cache.size() + secondCache.size()) { + INFO_LOG(G3D, "Texture cached cleared from %i textures", (int)(cache.size() + secondCache.size())); + cache.clear(); + secondCache.clear(); + cacheSizeEstimate_ = 0; + secondCacheSizeEstimate_ = 0; + } + fbTexInfo_.clear(); + videos_.clear(); +} + +void TextureCacheD3D11::DeleteTexture(TexCache::iterator it) { + ReleaseTexture(&it->second); + auto fbInfo = fbTexInfo_.find(it->first); + if (fbInfo != fbTexInfo_.end()) { + fbTexInfo_.erase(fbInfo); + } + + cacheSizeEstimate_ -= EstimateTexMemoryUsage(&it->second); + cache.erase(it); +} + +void TextureCacheD3D11::ForgetLastTexture() { + lastBoundTexture = INVALID_TEX; + gstate_c.Dirty(DIRTY_TEXTURE_PARAMS); +} + +// Removes old textures. +void TextureCacheD3D11::Decimate() { + if (--decimationCounter_ <= 0) { + decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL; + } else { + return; + } + + if (cacheSizeEstimate_ >= TEXCACHE_MIN_PRESSURE) { + const u32 had = cacheSizeEstimate_; + + context_->PSSetShaderResources(0, 1, nullptr); + lastBoundTexture = INVALID_TEX; + int killAge = lowMemoryMode_ ? TEXTURE_KILL_AGE_LOWMEM : TEXTURE_KILL_AGE; + for (TexCache::iterator iter = cache.begin(); iter != cache.end(); ) { + if (iter->second.lastFrame + killAge < gpuStats.numFlips) { + DeleteTexture(iter++); + } else { + ++iter; + } + } + + VERBOSE_LOG(G3D, "Decimated texture cache, saved %d estimated bytes - now %d bytes", had - cacheSizeEstimate_, cacheSizeEstimate_); + } + + if (g_Config.bTextureSecondaryCache && secondCacheSizeEstimate_ >= TEXCACHE_SECOND_MIN_PRESSURE) { + const u32 had = secondCacheSizeEstimate_; + + for (TexCache::iterator iter = secondCache.begin(); iter != secondCache.end(); ) { + // In low memory mode, we kill them all. + if (lowMemoryMode_ || iter->second.lastFrame + TEXTURE_KILL_AGE < gpuStats.numFlips) { + ReleaseTexture(&iter->second); + secondCache.erase(iter++); + } else { + ++iter; + } + } + + VERBOSE_LOG(G3D, "Decimated second texture cache, saved %d estimated bytes - now %d bytes", had - secondCacheSizeEstimate_, secondCacheSizeEstimate_); + } + + DecimateVideos(); +} + +DXGI_FORMAT getClutDestFormatD3D11(GEPaletteFormat format) { + switch (format) { + case GE_CMODE_16BIT_ABGR4444: + return DXGI_FORMAT_B4G4R4A4_UNORM; + case GE_CMODE_16BIT_ABGR5551: + return DXGI_FORMAT_B5G5R5A1_UNORM; + case GE_CMODE_16BIT_BGR5650: + return DXGI_FORMAT_B5G6R5_UNORM; + case GE_CMODE_32BIT_ABGR8888: + return DXGI_FORMAT_R8G8B8A8_UNORM; + } + // Should never be here ! + return DXGI_FORMAT_R8G8B8A8_UNORM; +} + +void TextureCacheD3D11::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key) { + // TODO: Make GetSamplingParams write SamplerCacheKey directly + int minFilt; + int magFilt; + bool sClamp; + bool tClamp; + float lodBias; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, entry.maxLevel, entry.addr); + key.minFilt = minFilt & 1; + key.mipEnable = (minFilt >> 2) & 1; + key.mipFilt = (minFilt >> 1) & 1; + key.magFilt = magFilt & 1; + key.sClamp = sClamp; + key.tClamp = tClamp; + key.maxLevel = entry.maxLevel; + /* + if (entry.maxLevel != 0) { + if (force || entry.lodBias != lodBias) { + if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + GETexLevelMode mode = gstate.getTexLevelMode(); + switch (mode) { + case GE_TEXLEVEL_MODE_AUTO: + // TODO + break; + case GE_TEXLEVEL_MODE_CONST: + // Sigh, LOD_BIAS is not even in ES 3.0.. + break; + case GE_TEXLEVEL_MODE_SLOPE: + // TODO + break; + } + } + entry.lodBias = lodBias; + } + } + */ + + if (entry.framebuffer) { + WARN_LOG_REPORT_ONCE(wrongFramebufAttach, G3D, "Framebuffer still attached in UpdateSamplingParams()?"); + } +} + +void TextureCacheD3D11::SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, SamplerCacheKey &key) { + int minFilt; + int magFilt; + bool sClamp; + bool tClamp; + float lodBias; + GetSamplingParams(minFilt, magFilt, sClamp, tClamp, lodBias, 0, 0); + + key.minFilt = minFilt & 1; + key.mipFilt = 0; + key.magFilt = magFilt & 1; + key.sClamp = sClamp; + key.tClamp = tClamp; + + // Often the framebuffer will not match the texture size. We'll wrap/clamp in the shader in that case. + // This happens whether we have OES_texture_npot or not. + int w = gstate.getTextureWidth(0); + int h = gstate.getTextureHeight(0); + if (w != bufferWidth || h != bufferHeight) { + key.sClamp = true; + key.tClamp = true; + } +} + +void TextureCacheD3D11::StartFrame() { + lastBoundTexture = INVALID_TEX; + timesInvalidatedAllThisFrame_ = 0; + + if (texelsScaledThisFrame_) { + // INFO_LOG(G3D, "Scaled %i texels", texelsScaledThisFrame_); + } + texelsScaledThisFrame_ = 0; + if (clearCacheNextFrame_) { + Clear(true); + clearCacheNextFrame_ = false; + } else { + Decimate(); + } +} + +static inline u32 MiniHash(const u32 *ptr) { + return ptr[0]; +} + +void TextureCacheD3D11::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) { + const u32 clutBaseBytes = clutBase * (clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16)); + // Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier. + // If not, we're going to hash random data, which hopefully doesn't cause a performance issue. + // + // TODO: Actually, this seems like a hack. The game can upload part of a CLUT and reference other data. + // clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash + // unrelated old entries for small palettes. + // Adding clutBaseBytes may just be mitigating this for some usage patterns. + const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); + + clutHash_ = DoReliableHash32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + clutBuf_ = clutBufRaw_; + + // Special optimization: fonts typically draw clut4 with just alpha values in a single color. + clutAlphaLinear_ = false; + clutAlphaLinearColor_ = 0; + if (clutFormat == GE_CMODE_16BIT_ABGR4444 && clutIndexIsSimple) { + const u16_le *clut = GetCurrentClut(); + clutAlphaLinear_ = true; + clutAlphaLinearColor_ = clut[15] & 0x0FFF; + for (int i = 0; i < 16; ++i) { + u16 step = clutAlphaLinearColor_ | (i << 12); + if (clut[i] != step) { + clutAlphaLinear_ = false; + break; + } + } + } + + clutLastFormat_ = gstate.clutformat; +} + +inline u32 TextureCacheD3D11::GetCurrentClutHash() { + return clutHash_; +} + +void TextureCacheD3D11::Unbind() { + context_->PSSetShaderResources(0, 1, nullptr); +} + +void TextureCacheD3D11::ApplyTexture() { + TexCacheEntry *entry = nextTexture_; + if (entry == nullptr) { + return; + } + nextTexture_ = nullptr; + + UpdateMaxSeenV(entry, gstate.isModeThrough()); + + bool replaceImages = false; + if (nextNeedsRebuild_) { + if (nextNeedsRehash_) { + // Update the hash on the texture. + int w = gstate.getTextureWidth(0); + int h = gstate.getTextureHeight(0); + entry->fullhash = QuickTexHash(replacer, entry->addr, entry->bufw, w, h, GETextureFormat(entry->format), entry); + } + if (nextNeedsChange_) { + // This texture existed previously, let's handle the change. + replaceImages = HandleTextureChange(entry, nextChangeReason_, false, true); + } + + // We actually build afterward (shared with rehash rebuild.) + } else if (nextNeedsRehash_) { + // Okay, this matched and didn't change - but let's check the hash. Maybe it will change. + bool doDelete = true; + if (!CheckFullHash(entry, doDelete)) { + replaceImages = HandleTextureChange(entry, "hash fail", true, doDelete); + nextNeedsRebuild_ = true; + } else if (nextTexture_ != nullptr) { + // Secondary cache picked a different texture, use it. + entry = nextTexture_; + nextTexture_ = nullptr; + UpdateMaxSeenV(entry, gstate.isModeThrough()); + } + } + + // Okay, now actually rebuild the texture if needed. + if (nextNeedsRebuild_) { + BuildTexture(entry, replaceImages); + } + + entry->lastFrame = gpuStats.numFlips; + if (entry->framebuffer) { + ApplyTextureFramebuffer(entry, entry->framebuffer); + } else { + ID3D11ShaderResourceView *textureView = DxView(entry); + if (textureView != lastBoundTexture) { + context_->PSSetShaderResources(0, 1, &textureView); + lastBoundTexture = textureView; + } + SamplerCacheKey key; + UpdateSamplingParams(*entry, key); + ID3D11SamplerState *state = samplerCache_.GetOrCreateSampler(device_, key); + context_->PSSetSamplers(0, 1, &state); + gstate_c.textureFullAlpha = entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL; + gstate_c.textureSimpleAlpha = entry->GetAlphaStatus() != TexCacheEntry::STATUS_ALPHA_UNKNOWN; + } +} + +class TextureShaderApplierD3D11 { +public: + struct Pos { + Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { + } + Pos() { + } + + float x; + float y; + float z; + }; + struct UV { + UV(float u_, float v_) : u(u_), v(v_) { + } + UV() { + } + + float u; + float v; + }; + + struct PosUV { + Pos pos; + UV uv; + }; + + TextureShaderApplierD3D11(ID3D11DeviceContext *context, ID3D11PixelShader *pshader, float bufferW, float bufferH, int renderW, int renderH, float xoff, float yoff) + : context_(context), pshader_(pshader), bufferW_(bufferW), bufferH_(bufferH), renderW_(renderW), renderH_(renderH) { + static const Pos pos[4] = { + { -1, 1, 0 }, + { 1, 1, 0 }, + { 1, -1, 0 }, + { -1, -1, 0 }, + }; + static const UV uv[4] = { + { 0, 0 }, + { 1, 0 }, + { 1, 1 }, + { 0, 1 }, + }; + + for (int i = 0; i < 4; ++i) { + verts_[i].pos = pos[i]; + verts_[i].pos.x += xoff; + verts_[i].pos.y += yoff; + verts_[i].uv = uv[i]; + } + } + + void ApplyBounds(const KnownVertexBounds &bounds, u32 uoff, u32 voff, float xoff, float yoff) { + // If min is not < max, then we don't have values (wasn't set during decode.) + if (bounds.minV < bounds.maxV) { + const float invWidth = 1.0f / bufferW_; + const float invHeight = 1.0f / bufferH_; + // Inverse of half = double. + const float invHalfWidth = invWidth * 2.0f; + const float invHalfHeight = invHeight * 2.0f; + + const int u1 = bounds.minU + uoff; + const int v1 = bounds.minV + voff; + const int u2 = bounds.maxU + uoff; + const int v2 = bounds.maxV + voff; + + const float left = u1 * invHalfWidth - 1.0f + xoff; + const float right = u2 * invHalfWidth - 1.0f + xoff; + const float top = v1 * invHalfHeight - 1.0f + yoff; + const float bottom = v2 * invHalfHeight - 1.0f + yoff; + // Points are: BL, BR, TR, TL. + verts_[0].pos = Pos(left, bottom, -1.0f); + verts_[1].pos = Pos(right, bottom, -1.0f); + verts_[2].pos = Pos(right, top, -1.0f); + verts_[3].pos = Pos(left, top, -1.0f); + + // And also the UVs, same order. + const float uvleft = u1 * invWidth; + const float uvright = u2 * invWidth; + const float uvtop = v1 * invHeight; + const float uvbottom = v2 * invHeight; + verts_[0].uv = UV(uvleft, uvbottom); + verts_[1].uv = UV(uvright, uvbottom); + verts_[2].uv = UV(uvright, uvtop); + verts_[3].uv = UV(uvleft, uvtop); + } + } + + void Use(ID3D11VertexShader *vshader, ID3D11InputLayout *decl) { + context_->PSSetShader(pshader_, 0, 0); + context_->VSSetShader(vshader, 0, 0); + context_->IASetInputLayout(decl); + } + + void Shade() { + D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)renderW_, (float)renderH_, 0.0f, 1.0f }; + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF); + context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0xFF); + context_->RSSetState(stockD3D11.rasterStateNoCull); + context_->RSSetViewports(1, &vp); + context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context_->IASetVertexBuffers(0, 1, &vbuffer_, &stride_, &offset_); + context_->Draw(2, 0); + } + +protected: + ID3D11DeviceContext *context_; + ID3D11PixelShader *pshader_; + ID3D11Buffer *vbuffer_; + PosUV verts_[4]; + UINT stride_ = sizeof(PosUV); + UINT offset_ = 0; + float bufferW_; + float bufferH_; + int renderW_; + int renderH_; +}; + +void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { + ID3D11PixelShader *pshader = nullptr; + const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); + if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) { + pshader = depalShaderCache_->GetDepalettizePixelShader(clutFormat, framebuffer->drawnFormat); + } + + if (pshader) { + ID3D11ShaderResourceView *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); + + Draw::Framebuffer *depalFBO = framebufferManagerD3D11_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888); + draw_->BindFramebufferAsRenderTarget(depalFBO); + shaderManager_->DirtyLastShader(); + draw_->BindPipeline(nullptr); + + float xoff = -0.5f / framebuffer->renderWidth; + float yoff = 0.5f / framebuffer->renderHeight; + + TextureShaderApplierD3D11 shaderApply(context_, pshader, framebuffer->bufferWidth, framebuffer->bufferHeight, framebuffer->renderWidth, framebuffer->renderHeight, xoff, yoff); + shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset, xoff, yoff); + shaderApply.Use(depalShaderCache_->GetDepalettizeVertexShader(), depalShaderCache_->GetInputLayout()); + + context_->PSSetShaderResources(1, 1, &clutTexture); + context_->PSSetSamplers(1, 1, &stockD3D11.samplerPoint2DWrap); + framebufferManagerD3D11_->BindFramebufferColor(0, framebuffer, BINDFBCOLOR_SKIP_COPY); + context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DWrap); + shaderApply.Shade(); + + draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); + + const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); + const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor; + + TexCacheEntry::Status alphaStatus = CheckAlpha(clutBuf_, getClutDestFormatD3D11(clutFormat), clutTotalColors, clutTotalColors, 1); + gstate_c.textureFullAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL; + gstate_c.textureSimpleAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE; + } else { + entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE; + + framebufferManagerD3D11_->BindFramebufferColor(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); + + gstate_c.textureFullAlpha = gstate.getTextureFormat() == GE_TFMT_5650; + gstate_c.textureSimpleAlpha = gstate_c.textureFullAlpha; + } + + framebufferManagerD3D11_->RebindFramebuffer(); + SamplerCacheKey samplerKey; + SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight, samplerKey); + ID3D11SamplerState *state = samplerCache_.GetOrCreateSampler(device_, samplerKey); + context_->PSSetSamplers(0, 1, &state); + lastBoundTexture = INVALID_TEX; +} + +void TextureCacheD3D11::SetTexture(bool force) { +#ifdef DEBUG_TEXTURES + if (SetDebugTexture()) { + // A different texture was bound, let's rebind next time. + lastBoundTexture = INVALID_TEX; + return; + } +#endif + + if (force) { + lastBoundTexture = INVALID_TEX; + } + + u32 texaddr = gstate.getTextureAddress(0); + if (!Memory::IsValidAddress(texaddr)) { + // Bind a null texture and return. + context_->PSSetShaderResources(0, 1, nullptr); + lastBoundTexture = INVALID_TEX; + return; + } + + const u16 dim = gstate.getTextureDimension(0); + int w = gstate.getTextureWidth(0); + int h = gstate.getTextureHeight(0); + + GETextureFormat format = gstate.getTextureFormat(); + if (format >= 11) { + ERROR_LOG_REPORT(G3D, "Unknown texture format %i", format); + // TODO: Better assumption? + format = GE_TFMT_5650; + } + bool hasClut = gstate.isTextureFormatIndexed(); + + // Ignore uncached/kernel when caching. + u32 cluthash; + if (hasClut) { + if (clutLastFormat_ != gstate.clutformat) { + // We update here because the clut format can be specified after the load. + UpdateCurrentClut(gstate.getClutPaletteFormat(), gstate.getClutIndexStartPos(), gstate.isClutIndexSimple()); + } + cluthash = GetCurrentClutHash() ^ gstate.clutformat; + } else { + cluthash = 0; + } + u64 cachekey = TexCacheEntry::CacheKey(texaddr, format, dim, cluthash); + + int bufw = GetTextureBufw(0, texaddr, format); + u8 maxLevel = gstate.getTextureMaxLevel(); + + u32 texhash = MiniHash((const u32 *)Memory::GetPointer(texaddr)); + + TexCache::iterator iter = cache.find(cachekey); + TexCacheEntry *entry = NULL; + gstate_c.needShaderTexClamp = false; + gstate_c.bgraTexture = true; + gstate_c.skipDrawReason &= ~SKIPDRAW_BAD_FB_TEXTURE; + bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; + + if (iter != cache.end()) { + entry = &iter->second; + // Validate the texture still matches the cache entry. + bool match = entry->Matches(dim, format, maxLevel); + const char *reason = "different params"; + + // Check for FBO - slow! + if (entry->framebuffer) { + if (match) { + if (hasClut && clutRenderAddress_ != 0xFFFFFFFF) { + WARN_LOG_REPORT_ONCE(clutAndTexRender, G3D, "Using rendered texture with rendered CLUT: texfmt=%d, clutfmt=%d", gstate.getTextureFormat(), gstate.getClutPaletteFormat()); + } + + SetTextureFramebuffer(entry, entry->framebuffer); + return; + } else { + // Make sure we re-evaluate framebuffers. + DetachFramebuffer(entry, texaddr, entry->framebuffer); + reason = "detached framebuf"; + match = false; + } + } + + bool rehash = entry->GetHashStatus() == TexCacheEntry::STATUS_UNRELIABLE; + + // First let's see if another texture with the same address had a hashfail. + if (entry->status & TexCacheEntry::STATUS_CLUT_RECHECK) { + // Always rehash in this case, if one changed the rest all probably did. + rehash = true; + entry->status &= ~TexCacheEntry::STATUS_CLUT_RECHECK; + } else if (!gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE)) { + // Okay, just some parameter change - the data didn't change, no need to rehash. + rehash = false; + } + + if (match) { + if (entry->lastFrame != gpuStats.numFlips) { + u32 diff = gpuStats.numFlips - entry->lastFrame; + entry->numFrames++; + + if (entry->framesUntilNextFullHash < diff) { + // Exponential backoff up to 512 frames. Textures are often reused. + if (entry->numFrames > 32) { + // Also, try to add some "randomness" to avoid rehashing several textures the same frame. + entry->framesUntilNextFullHash = std::min(512, entry->numFrames) + ((intptr_t)entry->texturePtr & 15); + } else { + entry->framesUntilNextFullHash = entry->numFrames; + } + rehash = true; + } else { + entry->framesUntilNextFullHash -= diff; + } + } + + // If it's not huge or has been invalidated many times, recheck the whole texture. + if (entry->invalidHint > 180 || (entry->invalidHint > 15 && (dim >> 8) < 9 && (dim & 0xF) < 9)) { + entry->invalidHint = 0; + rehash = true; + } + + if (texhash != entry->hash) { + match = false; + } else if (entry->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { + rehash = false; + } + } + + if (match && (entry->status & TexCacheEntry::STATUS_TO_SCALE) && standardScaleFactor_ != 1 && texelsScaledThisFrame_ < TEXCACHE_MAX_TEXELS_SCALED) { + if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) == 0) { + // INFO_LOG(G3D, "Reloading texture to do the scaling we skipped.."); + match = false; + reason = "scaling"; + } + } + + if (match) { + // TODO: Mark the entry reliable if it's been safe for long enough? + //got one! + if (entry->texturePtr != lastBoundTexture) { + gstate_c.curTextureWidth = w; + gstate_c.curTextureHeight = h; + } + if (rehash) { + // Update in case any of these changed. + entry->sizeInRAM = (textureBitsPerPixel[format] * bufw * h / 2) / 8; + entry->bufw = bufw; + entry->cluthash = cluthash; + } + + nextTexture_ = entry; + nextNeedsRehash_ = rehash; + nextNeedsChange_ = false; + // Might need a rebuild if the hash fails. + nextNeedsRebuild_ = false; + VERBOSE_LOG(G3D, "Texture at %08x Found in Cache, applying", texaddr); + return; //Done! + } else { + nextChangeReason_ = reason; + nextNeedsChange_ = true; + } + } else { + VERBOSE_LOG(G3D, "No texture in cache, decoding..."); + TexCacheEntry entryNew = { 0 }; + cache[cachekey] = entryNew; + + if (hasClut && clutRenderAddress_ != 0xFFFFFFFF) { + WARN_LOG_REPORT_ONCE(clutUseRender, G3D, "Using texture with rendered CLUT: texfmt=%d, clutfmt=%d", gstate.getTextureFormat(), gstate.getClutPaletteFormat()); + } + + entry = &cache[cachekey]; + if (g_Config.bTextureBackoffCache) { + entry->status = TexCacheEntry::STATUS_HASHING; + } else { + entry->status = TexCacheEntry::STATUS_UNRELIABLE; + } + + nextNeedsChange_ = false; + } + + // We have to decode it, let's setup the cache entry first. + entry->addr = texaddr; + entry->hash = texhash; + entry->dim = dim; + entry->format = format; + entry->maxLevel = maxLevel; + + // This would overestimate the size in many case so we underestimate instead + // to avoid excessive clearing caused by cache invalidations. + entry->sizeInRAM = (textureBitsPerPixel[format] * bufw * h / 2) / 8; + entry->bufw = bufw; + + entry->cluthash = cluthash; + + gstate_c.curTextureWidth = w; + gstate_c.curTextureHeight = h; + + // Before we go reading the texture from memory, let's check for render-to-texture. + // We must do this early so we have the right w/h. + entry->framebuffer = 0; + for (size_t i = 0, n = fbCache_.size(); i < n; ++i) { + auto framebuffer = fbCache_[i]; + AttachFramebuffer(entry, framebuffer->fb_address, framebuffer); + } + + // If we ended up with a framebuffer, attach it - no texture decoding needed. + if (entry->framebuffer) { + SetTextureFramebuffer(entry, entry->framebuffer); + } + + nextTexture_ = entry; + nextNeedsRehash_ = entry->framebuffer == nullptr; + // We still need to rebuild, to allocate a texture. But we'll bail early. + nextNeedsRebuild_ = true; +} + +bool TextureCacheD3D11::CheckFullHash(TexCacheEntry *const entry, bool &doDelete) { + bool hashFail = false; + int w = gstate.getTextureWidth(0); + int h = gstate.getTextureHeight(0); + u32 fullhash = QuickTexHash(replacer, entry->addr, entry->bufw, w, h, GETextureFormat(entry->format), entry); + if (fullhash != entry->fullhash) { + hashFail = true; + } else { + if (g_Config.bTextureBackoffCache) { + if (entry->GetHashStatus() != TexCacheEntry::STATUS_HASHING && entry->numFrames > TexCacheEntry::FRAMES_REGAIN_TRUST) { + // Reset to STATUS_HASHING. + entry->SetHashStatus(TexCacheEntry::STATUS_HASHING); + entry->status &= ~TexCacheEntry::STATUS_CHANGE_FREQUENT; + } + } else if (entry->numFrames > TEXCACHE_FRAME_CHANGE_FREQUENT_REGAIN_TRUST) { + entry->status &= ~TexCacheEntry::STATUS_CHANGE_FREQUENT; + } + } + + if (hashFail) { + entry->status |= TexCacheEntry::STATUS_UNRELIABLE; + if (entry->numFrames < TEXCACHE_FRAME_CHANGE_FREQUENT) { + if (entry->status & TexCacheEntry::STATUS_FREE_CHANGE) { + entry->status &= ~TexCacheEntry::STATUS_FREE_CHANGE; + } else { + entry->status |= TexCacheEntry::STATUS_CHANGE_FREQUENT; + } + } + entry->numFrames = 0; + + // Don't give up just yet. Let's try the secondary cache if it's been invalidated before. + // If it's failed a bunch of times, then the second cache is just wasting time and VRAM. + if (g_Config.bTextureSecondaryCache) { + if (entry->numInvalidated > 2 && entry->numInvalidated < 128 && !lowMemoryMode_) { + u64 secondKey = fullhash | (u64)entry->cluthash << 32; + TexCache::iterator secondIter = secondCache.find(secondKey); + if (secondIter != secondCache.end()) { + TexCacheEntry *secondEntry = &secondIter->second; + if (secondEntry->Matches(entry->dim, entry->format, entry->maxLevel)) { + // Reset the numInvalidated value lower, we got a match. + if (entry->numInvalidated > 8) { + --entry->numInvalidated; + } + nextTexture_ = secondEntry; + return true; + } + } else { + secondKey = entry->fullhash | ((u64)entry->cluthash << 32); + secondCacheSizeEstimate_ += EstimateTexMemoryUsage(entry); + secondCache[secondKey] = *entry; + doDelete = false; + } + } + } + + // We know it failed, so update the full hash right away. + entry->fullhash = fullhash; + return false; + } + + return true; +} + +bool TextureCacheD3D11::HandleTextureChange(TexCacheEntry *const entry, const char *reason, bool initialMatch, bool doDelete) { + bool replaceImages = false; + + cacheSizeEstimate_ -= EstimateTexMemoryUsage(entry); + entry->numInvalidated++; + gpuStats.numTextureInvalidations++; + DEBUG_LOG(G3D, "Texture different or overwritten, reloading at %08x: %s", entry->addr, reason); + if (doDelete) { + if (initialMatch && standardScaleFactor_ == 1 && (entry->status & TexCacheEntry::STATUS_IS_SCALED) == 0) { + // Actually, if size and number of levels match, let's try to avoid deleting and recreating. + // Instead, let's use glTexSubImage to replace the images. + replaceImages = true; + } else { + if (entry->texturePtr == lastBoundTexture) { + lastBoundTexture = INVALID_TEX; + } + ReleaseTexture(entry); + entry->status &= ~TexCacheEntry::STATUS_IS_SCALED; + } + } + // Clear the reliable bit if set. + if (entry->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { + entry->SetHashStatus(TexCacheEntry::STATUS_HASHING); + } + + // Also, mark any textures with the same address but different clut. They need rechecking. + if (entry->cluthash != 0) { + const u64 cachekeyMin = (u64)(entry->addr & 0x3FFFFFFF) << 32; + const u64 cachekeyMax = cachekeyMin + (1ULL << 32); + for (auto it = cache.lower_bound(cachekeyMin), end = cache.upper_bound(cachekeyMax); it != end; ++it) { + if (it->second.cluthash != entry->cluthash) { + it->second.status |= TexCacheEntry::STATUS_CLUT_RECHECK; + } + } + } + + return replaceImages; +} + +void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry, bool replaceImages) { + entry->status &= ~TexCacheEntry::STATUS_ALPHA_MASK; + + // For the estimate, we assume cluts always point to 8888 for simplicity. + cacheSizeEstimate_ += EstimateTexMemoryUsage(entry); + + // TODO: If a framebuffer is attached here, might end up with a bad entry.texture. + // Should just always create one here or something (like GLES.) + + if (entry->framebuffer) { + // Nothing else to do here. + return; + } + + if ((entry->bufw == 0 || (gstate.texbufwidth[0] & 0xf800) != 0) && entry->addr >= PSP_GetKernelMemoryEnd()) { + ERROR_LOG_REPORT(G3D, "Texture with unexpected bufw (full=%d)", gstate.texbufwidth[0] & 0xffff); + // Proceeding here can cause a crash. + return; + } + + // Adjust maxLevel to actually present levels.. + bool badMipSizes = false; + int maxLevel = entry->maxLevel; + for (int i = 0; i <= maxLevel; i++) { + // If encountering levels pointing to nothing, adjust max level. + u32 levelTexaddr = gstate.getTextureAddress(i); + if (!Memory::IsValidAddress(levelTexaddr)) { + maxLevel = i - 1; + break; + } + + if (i > 0 && gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { + int tw = gstate.getTextureWidth(i); + int th = gstate.getTextureHeight(i); + if (tw != 1 && tw != (gstate.getTextureWidth(i - 1) >> 1)) + badMipSizes = true; + else if (th != 1 && th != (gstate.getTextureHeight(i - 1) >> 1)) + badMipSizes = true; + } + } + + // In addition, simply don't load more than level 0 if g_Config.bMipMap is false. + if (!g_Config.bMipMap) { + maxLevel = 0; + } + + // If GLES3 is available, we can preallocate the storage, which makes texture loading more efficient. + DXGI_FORMAT dstFmt = GetDestFormat(GETextureFormat(entry->format), gstate.getClutPaletteFormat()); + + int scaleFactor = standardScaleFactor_; + + // Rachet down scale factor in low-memory mode. + if (lowMemoryMode_) { + // Keep it even, though, just in case of npot troubles. + scaleFactor = scaleFactor > 4 ? 4 : (scaleFactor > 2 ? 2 : 1); + } + + u64 cachekey = replacer.Enabled() ? entry->CacheKey() : 0; + int w = gstate.getTextureWidth(0); + int h = gstate.getTextureHeight(0); + ReplacedTexture &replaced = replacer.FindReplacement(cachekey, entry->fullhash, w, h); + if (replaced.GetSize(0, w, h)) { + if (replaceImages) { + // Since we're replacing the texture, we can't replace the image inside. + ReleaseTexture(entry); + replaceImages = false; + } + // We're replacing, so we won't scale. + scaleFactor = 1; + entry->status |= TexCacheEntry::STATUS_IS_SCALED; + if (g_Config.bMipMap) { + maxLevel = replaced.MaxLevel(); + badMipSizes = false; + } + } + + // Don't scale the PPGe texture. + if (entry->addr > 0x05000000 && entry->addr < PSP_GetKernelMemoryEnd()) + scaleFactor = 1; + if ((entry->status & TexCacheEntry::STATUS_CHANGE_FREQUENT) != 0 && scaleFactor != 1) { + // Remember for later that we /wanted/ to scale this texture. + entry->status |= TexCacheEntry::STATUS_TO_SCALE; + scaleFactor = 1; + } + + if (scaleFactor != 1) { + if (texelsScaledThisFrame_ >= TEXCACHE_MAX_TEXELS_SCALED) { + entry->status |= TexCacheEntry::STATUS_TO_SCALE; + scaleFactor = 1; + } else { + entry->status &= ~TexCacheEntry::STATUS_TO_SCALE; + entry->status |= TexCacheEntry::STATUS_IS_SCALED; + texelsScaledThisFrame_ += w * h; + } + } + + if (replaceImages) { + // Make sure it's not currently set. + context_->PSSetShaderResources(0, 1, nullptr); + } + + // Seems to cause problems in Tactics Ogre. + if (badMipSizes) { + maxLevel = 0; + } + + LoadTextureLevel(*entry, replaced, 0, maxLevel, replaceImages, scaleFactor, dstFmt); + ID3D11ShaderResourceView *textureView = DxView(entry); + if (!textureView) { + return; + } + + // Mipmapping is only enabled when texture scaling is disabled. + if (maxLevel > 0 && scaleFactor == 1) { + for (int i = 1; i <= maxLevel; i++) { + LoadTextureLevel(*entry, replaced, i, maxLevel, replaceImages, scaleFactor, dstFmt); + } + } + + if (replaced.Valid()) { + entry->SetAlphaStatus(TexCacheEntry::Status(replaced.AlphaStatus())); + } +} + +DXGI_FORMAT TextureCacheD3D11::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { + switch (format) { + case GE_TFMT_CLUT4: + case GE_TFMT_CLUT8: + case GE_TFMT_CLUT16: + case GE_TFMT_CLUT32: + return getClutDestFormatD3D11(clutFormat); + case GE_TFMT_4444: + return DXGI_FORMAT_B4G4R4A4_UNORM; + case GE_TFMT_5551: + return DXGI_FORMAT_B5G5R5A1_UNORM; + case GE_TFMT_5650: + return DXGI_FORMAT_B5G6R5_UNORM; + case GE_TFMT_8888: + case GE_TFMT_DXT1: + case GE_TFMT_DXT3: + case GE_TFMT_DXT5: + default: + return DXGI_FORMAT_R8G8B8A8_UNORM; + } +} + +TextureCacheD3D11::TexCacheEntry::Status TextureCacheD3D11::CheckAlpha(const u32 *pixelData, u32 dstFmt, int stride, int w, int h) { + CheckAlphaResult res; + switch (dstFmt) { + case DXGI_FORMAT_B4G4R4A4_UNORM: + res = CheckAlphaRGBA4444Basic(pixelData, stride, w, h); + break; + case DXGI_FORMAT_B5G5R5A1_UNORM: + res = CheckAlphaRGBA5551Basic(pixelData, stride, w, h); + break; + case DXGI_FORMAT_B5G6R5_UNORM: + // Never has any alpha. + res = CHECKALPHA_FULL; + break; + default: + res = CheckAlphaRGBA8888Basic(pixelData, stride, w, h); + break; + } + + return (TexCacheEntry::Status)res; +} + +ReplacedTextureFormat FromD3D11Format(u32 fmt) { + switch (fmt) { + case DXGI_FORMAT_B5G6R5_UNORM: return ReplacedTextureFormat::F_5650; + case DXGI_FORMAT_B5G5R5A1_UNORM: return ReplacedTextureFormat::F_5551; + case DXGI_FORMAT_B4G4R4A4_UNORM: return ReplacedTextureFormat::F_4444; + case DXGI_FORMAT_R8G8B8A8_UNORM: default: return ReplacedTextureFormat::F_8888; + } +} + +DXGI_FORMAT ToDXGIFormat(ReplacedTextureFormat fmt) { + switch (fmt) { + case ReplacedTextureFormat::F_5650: return DXGI_FORMAT_B5G6R5_UNORM; + case ReplacedTextureFormat::F_5551: return DXGI_FORMAT_B5G5R5A1_UNORM; + case ReplacedTextureFormat::F_4444: return DXGI_FORMAT_B4G4R4A4_UNORM; + case ReplacedTextureFormat::F_8888: default: return DXGI_FORMAT_R8G8B8A8_UNORM; + } +} + +void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, u32 dstFmt) { + int w = gstate.getTextureWidth(level); + int h = gstate.getTextureHeight(level); + + ID3D11Texture2D *texture = DxTex(&entry); + if (level == 0 && (!replaceImages || texture == nullptr)) { + // Create texture + int levels = scaleFactor == 1 ? maxLevel + 1 : 1; + int tw = w, th = h; + DXGI_FORMAT tfmt = (DXGI_FORMAT)(dstFmt); + if (replaced.GetSize(level, tw, th)) { + tfmt = ToDXGIFormat(replaced.Format(level)); + } else { + tw *= scaleFactor; + th *= scaleFactor; + if (scaleFactor > 1) { + tfmt = DXGI_FORMAT_R8G8B8A8_UNORM; + } + } + D3D11_TEXTURE2D_DESC desc{}; + // TODO: Make it immutable, will requires some code restructuring though. + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.ArraySize = 1; + desc.Width = tw; + desc.Height = th; + desc.MipLevels = levels; + + HRESULT hr = device_->CreateTexture2D(&desc, nullptr, &texture); + if (FAILED(hr)) { + INFO_LOG(G3D, "Failed to create D3D texture"); + ReleaseTexture(&entry); + return; + } + ID3D11ShaderResourceView *view; + hr = device_->CreateShaderResourceView(texture, nullptr, &view); + + entry.texturePtr = texture; + entry.textureView = view; + } + + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(texture, level, D3D11_MAP_WRITE_DISCARD, 0, &map); + + gpuStats.numTexturesDecoded++; + if (replaced.GetSize(level, w, h)) { + replaced.Load(level, map.pData, map.RowPitch); + dstFmt = ToDXGIFormat(replaced.Format(level)); + } else { + GETextureFormat tfmt = (GETextureFormat)entry.format; + GEPaletteFormat clutformat = gstate.getClutPaletteFormat(); + u32 texaddr = gstate.getTextureAddress(level); + int bufw = GetTextureBufw(level, texaddr, tfmt); + int bpp = dstFmt == DXGI_FORMAT_R8G8B8A8_UNORM ? 4 : 2; + + u32 *pixelData = (u32 *)map.pData; + int decPitch = map.RowPitch; + if (scaleFactor > 1) { + tmpTexBufRearrange.resize(std::max(bufw, w) * h); + pixelData = tmpTexBufRearrange.data(); + // We want to end up with a neatly packed texture for scaling. + decPitch = w * bpp; + } + + bool decSuccess = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false); + if (!decSuccess) { + memset(pixelData, 0, decPitch * h); + } + + if (scaleFactor > 1) { + scaler.ScaleAlways((u32 *)map.pData, pixelData, dstFmt, w, h, scaleFactor); + pixelData = (u32 *)map.pData; + + // We always end up at 8888. Other parts assume this. + assert(dstFmt == D3DFMT_A8R8G8B8); + bpp = sizeof(u32); + decPitch = w * bpp; + + if (decPitch != map.RowPitch) { + // Rearrange in place to match the requested pitch. + // (it can only be larger than w * bpp, and a match is likely.) + for (int y = h - 1; y >= 0; --y) { + memcpy((u8 *)map.pData + map.RowPitch * y, (u8 *)map.pData + decPitch * y, w * bpp); + } + decPitch = map.RowPitch; + } + } + + if ((entry.status & TexCacheEntry::STATUS_CHANGE_FREQUENT) == 0) { + TexCacheEntry::Status alphaStatus = CheckAlpha(pixelData, dstFmt, decPitch / bpp, w, h); + entry.SetAlphaStatus(alphaStatus, level); + } else { + entry.SetAlphaStatus(TexCacheEntry::STATUS_ALPHA_UNKNOWN); + } + + if (replacer.Enabled()) { + ReplacedTextureDecodeInfo replacedInfo; + replacedInfo.cachekey = entry.CacheKey(); + replacedInfo.hash = entry.fullhash; + replacedInfo.addr = entry.addr; + replacedInfo.isVideo = videos_.find(entry.addr & 0x3FFFFFFF) != videos_.end(); + replacedInfo.isFinal = (entry.status & TexCacheEntry::STATUS_TO_SCALE) == 0; + replacedInfo.scaleFactor = scaleFactor; + replacedInfo.fmt = FromD3D11Format(dstFmt); + + replacer.NotifyTextureDecoded(replacedInfo, pixelData, decPitch, level, w, h); + } + } + context_->Unmap(texture, level); +} + +bool TextureCacheD3D11::DecodeTexture(u8 *output, const GPUgstate &state) { + OutputDebugStringA("TextureCache::DecodeTexture : FixMe\r\n"); + return true; +} diff --git a/GPU/D3D11/TextureCacheD3D11.h b/GPU/D3D11/TextureCacheD3D11.h index 49cc4a292e..8d5effafd0 100644 --- a/GPU/D3D11/TextureCacheD3D11.h +++ b/GPU/D3D11/TextureCacheD3D11.h @@ -17,4 +17,113 @@ #pragma once -class TextureCacheD3D11 {}; \ No newline at end of file +#include + +#include "../Globals.h" +#include "GPU/GPU.h" +#include "GPU/GPUInterface.h" +#include "GPU/D3D11/TextureScalerD3D11.h" +#include "GPU/Common/TextureCacheCommon.h" + +struct VirtualFramebuffer; + +class FramebufferManagerD3D11; +class DepalShaderCacheD3D11; +class ShaderManagerD3D11; + +class SamplerCacheD3D11 { +public: + SamplerCacheD3D11() {} + ~SamplerCacheD3D11(); + ID3D11SamplerState *GetOrCreateSampler(ID3D11Device *device, const SamplerCacheKey &key); + +private: + std::map cache_; +}; + +class TextureCacheD3D11 : public TextureCacheCommon { +public: + TextureCacheD3D11(Draw::DrawContext *draw); + ~TextureCacheD3D11(); + + void SetTexture(bool force = false); + + void Clear(bool delete_them); + void StartFrame(); + + void SetFramebufferManager(FramebufferManagerD3D11 *fbManager); + void SetDepalShaderCache(DepalShaderCacheD3D11 *dpCache) { + depalShaderCache_ = dpCache; + } + void SetShaderManager(ShaderManagerD3D11 *sm) { + shaderManager_ = sm; + } + + // Only used by Qt UI? + bool DecodeTexture(u8 *output, const GPUgstate &state); + + void ForgetLastTexture() override; + + void SetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight, SamplerCacheKey &key); + + void ApplyTexture(); + +protected: + void Unbind() override; + +private: + void Decimate(); // Run this once per frame to get rid of old textures. + void DeleteTexture(TexCache::iterator it); + void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key); + void LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int maxLevel, bool replaceImages, int scaleFactor, u32 dstFmt); + DXGI_FORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; + TexCacheEntry::Status CheckAlpha(const u32 *pixelData, u32 dstFmt, int stride, int w, int h); + u32 GetCurrentClutHash(); + void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple); + void ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer); + + bool CheckFullHash(TexCacheEntry *const entry, bool &doDelete); + bool HandleTextureChange(TexCacheEntry *const entry, const char *reason, bool initialMatch, bool doDelete); + void BuildTexture(TexCacheEntry *const entry, bool replaceImages); + + ID3D11Device *device_; + ID3D11DeviceContext *context_; + + ID3D11Texture2D *DxTex(TexCacheEntry *entry) { + return (ID3D11Texture2D *)entry->texturePtr; + } + ID3D11ShaderResourceView *DxView(TexCacheEntry *entry) { + return (ID3D11ShaderResourceView *)entry->textureView; + } + void ReleaseTexture(TexCacheEntry *entry) { + ID3D11Texture2D *texture = (ID3D11Texture2D *)entry->texturePtr; + ID3D11ShaderResourceView *view = (ID3D11ShaderResourceView *)entry->textureView; + if (texture) { + texture->Release(); + entry->texturePtr = nullptr; + } + if (view) { + view->Release(); + entry->textureView = nullptr; + } + } + + TextureScalerD3D11 scaler; + + SamplerCacheD3D11 samplerCache_; + + u32 clutHash_; + + ID3D11ShaderResourceView *lastBoundTexture; + float maxAnisotropyLevel; + + int decimationCounter_; + int texelsScaledThisFrame_; + int timesInvalidatedAllThisFrame_; + + FramebufferManagerD3D11 *framebufferManagerD3D11_; + DepalShaderCacheD3D11 *depalShaderCache_; + ShaderManagerD3D11 *shaderManager_; +}; + +DXGI_FORMAT getClutDestFormatD3D11(GEPaletteFormat format); diff --git a/GPU/D3D11/TextureScalerD3D11.cpp b/GPU/D3D11/TextureScalerD3D11.cpp new file mode 100644 index 0000000000..a71ca42c8f --- /dev/null +++ b/GPU/D3D11/TextureScalerD3D11.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include + +#include +#include "Common/ColorConv.h" +#include "Common/ThreadPools.h" +#include "GPU/Common/TextureScalerCommon.h" +#include "GPU/D3D11/TextureScalerD3D11.h" +#include "GPU/D3D11/GPU_D3D11.h" + +int TextureScalerD3D11::BytesPerPixel(u32 format) { + return format == GE_FORMAT_8888 ? 4 : 2; +} + +u32 TextureScalerD3D11::Get8888Format() { + return DXGI_FORMAT_R8G8B8A8_UNORM; +} + +void TextureScalerD3D11::ConvertTo8888(u32 format, u32* source, u32* &dest, int width, int height) { + switch (format) { + case GE_FORMAT_8888: + dest = source; // already fine + break; + + case GE_FORMAT_4444: + GlobalThreadPool::Loop(std::bind(&convert4444_dx9, (u16*)source, dest, width, std::placeholders::_1, std::placeholders::_2), 0, height); + break; + + case GE_FORMAT_565: + GlobalThreadPool::Loop(std::bind(&convert565_dx9, (u16*)source, dest, width, std::placeholders::_1, std::placeholders::_2), 0, height); + break; + + case GE_FORMAT_5551: + GlobalThreadPool::Loop(std::bind(&convert5551_dx9, (u16*)source, dest, width, std::placeholders::_1, std::placeholders::_2), 0, height); + break; + + default: + dest = source; + ERROR_LOG(G3D, "iXBRZTexScaling: unsupported texture format"); + } +} \ No newline at end of file diff --git a/GPU/D3D11/TextureScalerD3D11.h b/GPU/D3D11/TextureScalerD3D11.h new file mode 100644 index 0000000000..298045342a --- /dev/null +++ b/GPU/D3D11/TextureScalerD3D11.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "Common/CommonTypes.h" +#include "GPU/Common/TextureScalerCommon.h" + +class TextureScalerD3D11 : public TextureScalerCommon { +private: + // NOTE: We use GE formats, D3D11 doesn't support 4444 + void ConvertTo8888(u32 format, u32* source, u32* &dest, int width, int height) override; + int BytesPerPixel(u32 format) override; + u32 Get8888Format() override; +}; \ No newline at end of file diff --git a/GPU/D3D11/VertexShaderGeneratorD3D11.cpp b/GPU/D3D11/VertexShaderGeneratorD3D11.cpp index 22c90210d1..d069225b3b 100644 --- a/GPU/D3D11/VertexShaderGeneratorD3D11.cpp +++ b/GPU/D3D11/VertexShaderGeneratorD3D11.cpp @@ -1,5 +1,25 @@ +// Copyright (c) 2017- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "GPU/Common/ShaderCommon.h" #include "GPU/D3D11/VertexShaderGeneratorD3D11.h" +#include "GPU/Directx9/VertexShaderGeneratorDX9.h" void GenerateVertexShaderD3D11(const ShaderID &id, char *buffer, bool *usesLighting) { - + *usesLighting = true; + DX9::GenerateVertexShaderHLSL(id, buffer, HLSL_D3D11); } diff --git a/GPU/Directx9/DepalettizeShaderDX9.h b/GPU/Directx9/DepalettizeShaderDX9.h index a0450c1785..6a3ede46cb 100644 --- a/GPU/Directx9/DepalettizeShaderDX9.h +++ b/GPU/Directx9/DepalettizeShaderDX9.h @@ -16,7 +16,6 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include -#include #include #include "Common/CommonTypes.h" diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index f7ff990953..df14e0d4d7 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -920,7 +920,7 @@ bool DrawEngineDX9::IsCodePtrVertexDecoder(const u8 *ptr) const { return decJitCache_->IsInSpace(ptr); } -void DX9::DrawEngineDX9::TessellationDataTransferDX9::SendDataToShader(const float * pos, const float * tex, const float * col, int size, bool hasColor, bool hasTexCoords) +void DrawEngineDX9::TessellationDataTransferDX9::SendDataToShader(const float * pos, const float * tex, const float * col, int size, bool hasColor, bool hasTexCoords) { } diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index ef582c1e18..4118111908 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -942,8 +942,8 @@ void GPU_DX9::GetStats(char *buffer, size_t bufsize) { (int)textureCacheDX9_->NumLoadedTextures(), gpuStats.numTexturesDecoded, gpuStats.numTextureInvalidations, - shaderManagerDX9_->NumVertexShaders(), - shaderManagerDX9_->NumFragmentShaders() + shaderManagerDX9_->GetNumVertexShaders(), + shaderManagerDX9_->GetNumFragmentShaders() ); } diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/PixelShaderGeneratorDX9.cpp index ace6be1069..e63d362229 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/PixelShaderGeneratorDX9.cpp @@ -24,6 +24,7 @@ #include "GPU/ge_constants.h" #include "GPU/Common/GPUStateUtils.h" #include "GPU/GPUState.h" +#include "GPU/Common/ShaderUniforms.h" #define WRITE p+=sprintf @@ -33,7 +34,7 @@ namespace DX9 { // Missing: Z depth range // Also, logic ops etc, of course, as they are not supported in DX9. -bool GenerateFragmentShaderDX9(const ShaderID &id, char *buffer) { +bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage lang) { char *p = buffer; bool lmode = id.Bit(FS_BIT_LMODE); @@ -68,39 +69,43 @@ bool GenerateFragmentShaderDX9(const ShaderID &id, char *buffer) { StencilValueType replaceAlphaWithStencilType = (StencilValueType)id.Bits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4); - if (doTexture) - WRITE(p, "sampler tex : register(s0);\n"); - if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) { - if (replaceBlend == REPLACE_BLEND_COPY_FBO) { - WRITE(p, "float2 u_fbotexSize : register(c%i);\n", CONST_PS_FBOTEXSIZE); - WRITE(p, "sampler fbotex : register(s1);\n"); + if (lang == HLSL_DX9) { + if (doTexture) + WRITE(p, "sampler tex : register(s0);\n"); + if (!isModeClear && replaceBlend > REPLACE_BLEND_STANDARD) { + if (replaceBlend == REPLACE_BLEND_COPY_FBO) { + WRITE(p, "float2 u_fbotexSize : register(c%i);\n", CONST_PS_FBOTEXSIZE); + WRITE(p, "sampler fbotex : register(s1);\n"); + } + if (replaceBlendFuncA >= GE_SRCBLEND_FIXA) { + WRITE(p, "float3 u_blendFixA : register(c%i);\n", CONST_PS_BLENDFIXA); + } + if (replaceBlendFuncB >= GE_DSTBLEND_FIXB) { + WRITE(p, "float3 u_blendFixB : register(c%i);\n", CONST_PS_BLENDFIXB); + } } - if (replaceBlendFuncA >= GE_SRCBLEND_FIXA) { - WRITE(p, "float3 u_blendFixA : register(c%i);\n", CONST_PS_BLENDFIXA); + if (gstate_c.needShaderTexClamp && doTexture) { + WRITE(p, "float4 u_texclamp : register(c%i);\n", CONST_PS_TEXCLAMP); + if (textureAtOffset) { + WRITE(p, "float2 u_texclampoff : register(c%i);\n", CONST_PS_TEXCLAMPOFF); + } } - if (replaceBlendFuncB >= GE_DSTBLEND_FIXB) { - WRITE(p, "float3 u_blendFixB : register(c%i);\n", CONST_PS_BLENDFIXB); - } - } - if (gstate_c.needShaderTexClamp && doTexture) { - WRITE(p, "float4 u_texclamp : register(c%i);\n", CONST_PS_TEXCLAMP); - if (textureAtOffset) { - WRITE(p, "float2 u_texclampoff : register(c%i);\n", CONST_PS_TEXCLAMPOFF); - } - } - if (enableAlphaTest || enableColorTest) { - WRITE(p, "float4 u_alphacolorref : register(c%i);\n", CONST_PS_ALPHACOLORREF); - WRITE(p, "float4 u_alphacolormask : register(c%i);\n", CONST_PS_ALPHACOLORMASK); - } - if (stencilToAlpha && replaceAlphaWithStencilType == STENCIL_VALUE_UNIFORM) { - WRITE(p, "float u_stencilReplaceValue : register(c%i);\n", CONST_PS_STENCILREPLACE); - } - if (doTexture && texFunc == GE_TEXFUNC_BLEND) { - WRITE(p, "float3 u_texenv : register(c%i);\n", CONST_PS_TEXENV); - } - if (enableFog) { - WRITE(p, "float3 u_fogcolor : register(c%i);\n", CONST_PS_FOGCOLOR); + if (enableAlphaTest || enableColorTest) { + WRITE(p, "float4 u_alphacolorref : register(c%i);\n", CONST_PS_ALPHACOLORREF); + WRITE(p, "float4 u_alphacolormask : register(c%i);\n", CONST_PS_ALPHACOLORMASK); + } + if (stencilToAlpha && replaceAlphaWithStencilType == STENCIL_VALUE_UNIFORM) { + WRITE(p, "float u_stencilReplaceValue : register(c%i);\n", CONST_PS_STENCILREPLACE); + } + if (doTexture && texFunc == GE_TEXFUNC_BLEND) { + WRITE(p, "float3 u_texenv : register(c%i);\n", CONST_PS_TEXENV); + } + if (enableFog) { + WRITE(p, "float3 u_fogcolor : register(c%i);\n", CONST_PS_FOGCOLOR); + } + } else { + WRITE(p, "cbuffer base : register(b0) %s;\n", cb_baseStr); } if (enableAlphaTest) { @@ -122,7 +127,12 @@ bool GenerateFragmentShaderDX9(const ShaderID &id, char *buffer) { WRITE(p, " float2 v_fogdepth: TEXCOORD1;\n"); } WRITE(p, "};\n"); - WRITE(p, "float4 main( PS_IN In ) : COLOR\n"); + + if (lang == HLSL_DX9) { + WRITE(p, "float4 main( PS_IN In ) : COLOR\n"); + } else { + WRITE(p, "float4 main( PS_IN In ) : SV_Target\n"); + } WRITE(p, "{\n"); if (isModeClear) { diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.h b/GPU/Directx9/PixelShaderGeneratorDX9.h index a2373dbc15..19318248d9 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.h +++ b/GPU/Directx9/PixelShaderGeneratorDX9.h @@ -18,10 +18,11 @@ #pragma once #include "GPU/Common/ShaderId.h" +#include "GPU/Common/ShaderCommon.h" namespace DX9 { -bool GenerateFragmentShaderDX9(const ShaderID &id, char *buffer); +bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage lang = HLSL_DX9); #define CONST_PS_TEXENV 0 #define CONST_PS_ALPHACOLORREF 1 diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index dc57958fa9..1e852631e0 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -576,7 +576,7 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) { VSShader *vs; if (vsIter == vsCache_.end()) { // Vertex shader not in cache. Let's compile it. - GenerateVertexShaderDX9(VSID, codeBuffer_); + GenerateVertexShaderHLSL(VSID, codeBuffer_); vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform); if (vs->Failed()) { @@ -592,7 +592,7 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) { // next time and we'll do this over and over... // Can still work with software transform. - GenerateVertexShaderDX9(VSID, codeBuffer_); + GenerateVertexShaderHLSL(VSID, codeBuffer_); vs = new VSShader(device_, VSID, codeBuffer_, false); } @@ -606,7 +606,7 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) { PSShader *fs; if (fsIter == fsCache_.end()) { // Fragment shader not in cache. Let's compile it. - GenerateFragmentShaderDX9(FSID, codeBuffer_); + GenerateFragmentShaderHLSL(FSID, codeBuffer_); fs = new PSShader(device_, FSID, codeBuffer_); fsCache_[FSID] = fs; } else { diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index e721cd9f46..364802a539 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -86,8 +86,8 @@ public: void DirtyShader(); void DirtyLastShader(); - int NumVertexShaders() const { return (int)vsCache_.size(); } - int NumFragmentShaders() const { return (int)fsCache_.size(); } + int GetNumVertexShaders() const { return (int)vsCache_.size(); } + int GetNumFragmentShaders() const { return (int)fsCache_.size(); } std::vector DebugGetShaderIDs(DebugShaderType type); std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType); diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index cab431d1e5..eccb387ec8 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -1027,8 +1027,6 @@ void TextureCacheDX9::BuildTexture(TexCacheEntry *const entry, bool replaceImage if (replaced.Valid()) { entry->SetAlphaStatus(TexCacheEntry::Status(replaced.AlphaStatus())); } - - UpdateSamplingParams(*entry, true); } D3DFORMAT TextureCacheDX9::GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const { diff --git a/GPU/Directx9/TextureCacheDX9.h b/GPU/Directx9/TextureCacheDX9.h index 06df6117a9..2c5a8a8401 100644 --- a/GPU/Directx9/TextureCacheDX9.h +++ b/GPU/Directx9/TextureCacheDX9.h @@ -18,6 +18,7 @@ #pragma once #include + #include #include "../Globals.h" diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 86a7a92ce3..f2ddcac446 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -29,6 +29,7 @@ #include "GPU/Directx9/VertexShaderGeneratorDX9.h" #include "GPU/Common/VertexDecoderCommon.h" +#include "GPU/Common/ShaderUniforms.h" #undef WRITE @@ -54,7 +55,7 @@ enum DoLightComputation { LIGHT_FULL, }; -void GenerateVertexShaderDX9(const ShaderID &id, char *buffer) { +void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage lang) { char *p = buffer; const u32 vertType = gstate.vertType; @@ -105,74 +106,80 @@ void GenerateVertexShaderDX9(const ShaderID &id, char *buffer) { WRITE(p, "#pragma warning( disable : 3571 )\n"); - if (isModeThrough) { - WRITE(p, "float4x4 u_proj_through : register(c%i);\n", CONST_VS_PROJ_THROUGH); - } else { - WRITE(p, "float4x4 u_proj : register(c%i);\n", CONST_VS_PROJ); - // Add all the uniforms we'll need to transform properly. - } + if (lang == HLSL_DX9) { + if (isModeThrough) { + WRITE(p, "float4x4 u_proj_through : register(c%i);\n", CONST_VS_PROJ_THROUGH); + } else { + WRITE(p, "float4x4 u_proj : register(c%i);\n", CONST_VS_PROJ); + // Add all the uniforms we'll need to transform properly. + } - if (enableFog) { - WRITE(p, "float2 u_fogcoef : register(c%i);\n", CONST_VS_FOGCOEF); - } - if (useHWTransform || !hasColor) - WRITE(p, "float4 u_matambientalpha : register(c%i);\n", CONST_VS_MATAMBIENTALPHA); // matambient + matalpha + if (enableFog) { + WRITE(p, "float2 u_fogcoef : register(c%i);\n", CONST_VS_FOGCOEF); + } + if (useHWTransform || !hasColor) + WRITE(p, "float4 u_matambientalpha : register(c%i);\n", CONST_VS_MATAMBIENTALPHA); // matambient + matalpha - if (useHWTransform) { - // When transforming by hardware, we need a great deal more uniforms... - WRITE(p, "float4x3 u_world : register(c%i);\n", CONST_VS_WORLD); - WRITE(p, "float4x3 u_view : register(c%i);\n", CONST_VS_VIEW); - if (doTextureTransform) - WRITE(p, "float4x3 u_texmtx : register(c%i);\n", CONST_VS_TEXMTX); - if (enableBones) { + if (useHWTransform) { + // When transforming by hardware, we need a great deal more uniforms... + WRITE(p, "float4x3 u_world : register(c%i);\n", CONST_VS_WORLD); + WRITE(p, "float4x3 u_view : register(c%i);\n", CONST_VS_VIEW); + if (doTextureTransform) + WRITE(p, "float4x3 u_texmtx : register(c%i);\n", CONST_VS_TEXMTX); + if (enableBones) { #ifdef USE_BONE_ARRAY - WRITE(p, "float4x3 u_bone[%i] : register(c%i);\n", numBones, CONST_VS_BONE0); + WRITE(p, "float4x3 u_bone[%i] : register(c%i);\n", numBones, CONST_VS_BONE0); #else - for (int i = 0; i < numBoneWeights; i++) { - WRITE(p, "float4x3 u_bone%i : register(c%i);\n", i, CONST_VS_BONE0 + i * 3); - } + for (int i = 0; i < numBoneWeights; i++) { + WRITE(p, "float4x3 u_bone%i : register(c%i);\n", i, CONST_VS_BONE0 + i * 3); + } #endif - } - if (doTexture) { - WRITE(p, "float4 u_uvscaleoffset : register(c%i);\n", CONST_VS_UVSCALEOFFSET); - } - for (int i = 0; i < 4; i++) { - if (doLight[i] != LIGHT_OFF) { - // This is needed for shade mapping - WRITE(p, "float3 u_lightpos%i : register(c%i);\n", i, CONST_VS_LIGHTPOS + i); } - if (doLight[i] == LIGHT_FULL) { - GELightType type = static_cast(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2)); - GELightComputation comp = static_cast(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2)); - - if (type != GE_LIGHTTYPE_DIRECTIONAL) - WRITE(p, "float3 u_lightatt%i : register(c%i);\n", i, CONST_VS_LIGHTATT + i); - - if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) { - WRITE(p, "float3 u_lightdir%i : register(c%i);\n", i, CONST_VS_LIGHTDIR + i); - WRITE(p, "float u_lightangle%i : register(c%i);\n", i, CONST_VS_LIGHTANGLE + i); - WRITE(p, "float u_lightspotCoef%i : register(c%i);\n", i, CONST_VS_LIGHTSPOTCOEF + i); + if (doTexture) { + WRITE(p, "float4 u_uvscaleoffset : register(c%i);\n", CONST_VS_UVSCALEOFFSET); + } + for (int i = 0; i < 4; i++) { + if (doLight[i] != LIGHT_OFF) { + // This is needed for shade mapping + WRITE(p, "float3 u_lightpos%i : register(c%i);\n", i, CONST_VS_LIGHTPOS + i); } - WRITE(p, "float3 u_lightambient%i : register(c%i);\n", i, CONST_VS_LIGHTAMBIENT + i); - WRITE(p, "float3 u_lightdiffuse%i : register(c%i);\n", i, CONST_VS_LIGHTDIFFUSE + i); + if (doLight[i] == LIGHT_FULL) { + GELightType type = static_cast(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2)); + GELightComputation comp = static_cast(id.Bits(VS_BIT_LIGHT0_COMP + 4 * i, 2)); - if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) { - WRITE(p, "float3 u_lightspecular%i : register(c%i);\n", i, CONST_VS_LIGHTSPECULAR + i); + if (type != GE_LIGHTTYPE_DIRECTIONAL) + WRITE(p, "float3 u_lightatt%i : register(c%i);\n", i, CONST_VS_LIGHTATT + i); + + if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) { + WRITE(p, "float3 u_lightdir%i : register(c%i);\n", i, CONST_VS_LIGHTDIR + i); + WRITE(p, "float u_lightangle%i : register(c%i);\n", i, CONST_VS_LIGHTANGLE + i); + WRITE(p, "float u_lightspotCoef%i : register(c%i);\n", i, CONST_VS_LIGHTSPOTCOEF + i); + } + WRITE(p, "float3 u_lightambient%i : register(c%i);\n", i, CONST_VS_LIGHTAMBIENT + i); + WRITE(p, "float3 u_lightdiffuse%i : register(c%i);\n", i, CONST_VS_LIGHTDIFFUSE + i); + + if (comp != GE_LIGHTCOMP_ONLYDIFFUSE) { + WRITE(p, "float3 u_lightspecular%i : register(c%i);\n", i, CONST_VS_LIGHTSPECULAR + i); + } } } + if (enableLighting) { + WRITE(p, "float4 u_ambient : register(c%i);\n", CONST_VS_AMBIENT); + if ((gstate.materialupdate & 2) == 0 || !hasColor) + WRITE(p, "float3 u_matdiffuse : register(c%i);\n", CONST_VS_MATDIFFUSE); + // if ((gstate.materialupdate & 4) == 0) + WRITE(p, "float4 u_matspecular : register(c%i);\n", CONST_VS_MATSPECULAR); // Specular coef is contained in alpha + WRITE(p, "float3 u_matemissive : register(c%i);\n", CONST_VS_MATEMISSIVE); + } } - if (enableLighting) { - WRITE(p, "float4 u_ambient : register(c%i);\n", CONST_VS_AMBIENT); - if ((gstate.materialupdate & 2) == 0 || !hasColor) - WRITE(p, "float3 u_matdiffuse : register(c%i);\n", CONST_VS_MATDIFFUSE); - // if ((gstate.materialupdate & 4) == 0) - WRITE(p, "float4 u_matspecular : register(c%i);\n", CONST_VS_MATSPECULAR); // Specular coef is contained in alpha - WRITE(p, "float3 u_matemissive : register(c%i);\n", CONST_VS_MATEMISSIVE); - } - } - if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, "float4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE); + if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + WRITE(p, "float4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE); + } + } else { + WRITE(p, "cbuffer base : register(b0) %s;\n", cb_baseStr); + WRITE(p, "cbuffer lights: register(b1) %s;\n", cb_vs_lightsStr); + WRITE(p, "cbuffer bones : register(b2) %s;\n", cb_vs_bonesStr); } // And the "varyings". @@ -216,7 +223,11 @@ void GenerateVertexShaderDX9(const ShaderID &id, char *buffer) { } WRITE(p, "struct VS_OUT {\n"); - WRITE(p, " float4 gl_Position : POSITION;\n"); + if (lang == HLSL_DX9) { + WRITE(p, " float4 gl_Position : POSITION;\n"); + } else { + WRITE(p, " float4 gl_Position : SV_Position;\n"); + } if (doTexture) { WRITE(p, " float3 v_texcoord : TEXCOORD0;\n"); } diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.h b/GPU/Directx9/VertexShaderGeneratorDX9.h index ea43973b19..21601b989d 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.h +++ b/GPU/Directx9/VertexShaderGeneratorDX9.h @@ -25,7 +25,7 @@ namespace DX9 { // #define USE_BONE_ARRAY - void GenerateVertexShaderDX9(const ShaderID &id, char *buffer); + void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage lang = HLSL_DX9); #define CONST_VS_PROJ 0 #define CONST_VS_PROJ_THROUGH 4 diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 4942dbc9fd..05745727a6 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -1188,9 +1188,9 @@ void GPU_GLES::GetStats(char *buffer, size_t bufsize) { (int)textureCacheGL_->NumLoadedTextures(), gpuStats.numTexturesDecoded, gpuStats.numTextureInvalidations, - shaderManagerGL_->NumVertexShaders(), - shaderManagerGL_->NumFragmentShaders(), - shaderManagerGL_->NumPrograms()); + shaderManagerGL_->GetNumVertexShaders(), + shaderManagerGL_->GetNumFragmentShaders(), + shaderManagerGL_->GetNumPrograms()); } void GPU_GLES::ClearCacheNextFrame() { diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 3cc287305d..1da2b93a8b 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -1084,9 +1084,9 @@ void ShaderManagerGLES::Save(const std::string &filename) { header.version = CACHE_VERSION; header.reserved = 0; header.featureFlags = gstate_c.featureFlags; - header.numVertexShaders = NumVertexShaders(); - header.numFragmentShaders = NumFragmentShaders(); - header.numLinkedPrograms = NumPrograms(); + header.numVertexShaders = GetNumVertexShaders(); + header.numFragmentShaders = GetNumFragmentShaders(); + header.numLinkedPrograms = GetNumPrograms(); fwrite(&header, 1, sizeof(header), f); for (auto iter : vsCache_) { ShaderID id = iter.first; diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index cc7944bd18..7010acddca 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -155,9 +155,9 @@ public: void DirtyShader(); void DirtyLastShader(); // disables vertex arrays - int NumVertexShaders() const { return (int)vsCache_.size(); } - int NumFragmentShaders() const { return (int)fsCache_.size(); } - int NumPrograms() const { return (int)linkedShaderCache_.size(); } + int GetNumVertexShaders() const { return (int)vsCache_.size(); } + int GetNumFragmentShaders() const { return (int)fsCache_.size(); } + int GetNumPrograms() const { return (int)linkedShaderCache_.size(); } std::vector DebugGetShaderIDs(DebugShaderType type); std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType); diff --git a/GPU/GPU.cpp b/GPU/GPU.cpp index deff4fdf70..797c8cbb63 100644 --- a/GPU/GPU.cpp +++ b/GPU/GPU.cpp @@ -66,9 +66,8 @@ bool GPU_Init(GraphicsContext *ctx, Draw::DrawContext *draw) { #endif case GPUCORE_DIRECTX11: #if defined(_WIN32) - // SetGPU(new D3D11_GPU(ctx, draw)); - // break; - return false; + SetGPU(new GPU_D3D11(ctx, draw)); + break; #else return false; #endif diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index cd9fdeb5dd..195417444c 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -203,6 +203,7 @@ + @@ -210,6 +211,7 @@ + @@ -296,6 +298,7 @@ + @@ -303,7 +306,9 @@ + + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 07bfddc62f..b646468b14 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -249,6 +249,12 @@ D3D11 + + D3D11 + + + D3D11 + @@ -485,5 +491,14 @@ D3D11 + + D3D11 + + + D3D11 + + + D3D11 + \ No newline at end of file diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 77d1145e68..d3cf4472c3 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -78,16 +78,17 @@ static const VkComponentMapping VULKAN_1555_SWIZZLE = { VK_COMPONENT_SWIZZLE_B, static const VkComponentMapping VULKAN_565_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; static const VkComponentMapping VULKAN_8888_SWIZZLE = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; + +CachedTextureVulkan::~CachedTextureVulkan() { + delete texture_; +} + SamplerCache::~SamplerCache() { for (auto iter : cache_) { vulkan_->Delete().QueueDeleteSampler(iter.second); } } -CachedTextureVulkan::~CachedTextureVulkan() { - delete texture_; -} - VkSampler SamplerCache::GetOrCreateSampler(const SamplerCacheKey &key) { auto iter = cache_.find(key); if (iter != cache_.end()) { diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index 7a7b34c5c9..f0318a3f26 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -37,28 +37,6 @@ class VulkanTexture; class VulkanPushBuffer; class VulkanDeviceAllocator; -struct SamplerCacheKey { - SamplerCacheKey() : fullKey(0) {} - - union { - u32 fullKey; - struct { - bool mipEnable : 1; - bool minFilt : 1; - bool mipFilt : 1; - bool magFilt : 1; - bool sClamp : 1; - bool tClamp : 1; - int lodBias : 4; - int maxLevel : 4; - }; - }; - - bool operator < (const SamplerCacheKey &other) const { - return fullKey < other.fullKey; - } -}; - class CachedTextureVulkan { public: CachedTextureVulkan() : texture_(nullptr) { diff --git a/dx9sdk b/dx9sdk index a2e5de9de3..7324553f8f 160000 --- a/dx9sdk +++ b/dx9sdk @@ -1 +1 @@ -Subproject commit a2e5de9de341a8659aa1199e03636f5a4cea1318 +Subproject commit 7324553f8f4952a576c7f2d42df0accb0335d23c diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index b57f21ed12..d3f49fe2db 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -316,6 +316,8 @@ enum class NativeObject { CONTEXT, DEVICE, DEVICE_EX, + BACKBUFFER_COLOR_VIEW, + BACKBUFFER_DEPTH_VIEW, }; enum FBColorDepth { @@ -610,6 +612,7 @@ public: BindTextures(stage, 1, &texture); } // from sampler 0 and upwards + // Call this with 0 to signal that you have been drawing on your own, and need the state reset on the next pipeline bind. virtual void BindPipeline(Pipeline *pipeline) = 0; // TODO: Add more sophisticated draws with buffer offsets, and multidraws. diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 138b55ecf1..6550ca8d0f 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -100,6 +100,10 @@ public: return (uintptr_t)device_; case NativeObject::CONTEXT: return (uintptr_t)context_; + case NativeObject::BACKBUFFER_COLOR_VIEW: + return (uintptr_t)bbRenderTargetView_; + case NativeObject::BACKBUFFER_DEPTH_VIEW: + return (uintptr_t)bbDepthStencilView_; default: return 0; } @@ -792,6 +796,18 @@ void D3D11DrawContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) { } void D3D11DrawContext::BindPipeline(Pipeline *pipeline) { + if (pipeline == nullptr) { + // This is a signal to forget all our caching. + curBlend_ = nullptr; + curDepth_ = nullptr; + curRaster_ = nullptr; + curPS_ = nullptr; + curVS_ = nullptr; + curGS_ = nullptr; + curInputLayout_ = nullptr; + curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + } + D3D11Pipeline *dPipeline = (D3D11Pipeline *)pipeline; if (curPipeline_ == dPipeline) return; @@ -840,7 +856,6 @@ void D3D11DrawContext::ApplyCurrentState() { if (nextIndexBuffer_) { context_->IASetIndexBuffer(nextIndexBuffer_, DXGI_FORMAT_R32_UINT, nextIndexBufferOffset_); } - if (curPipeline_->dynamicUniforms) { context_->VSSetConstantBuffers(0, 1, &curPipeline_->dynamicUniforms); } From 76587ec61c7d220f80eb3c225e8b6871b008086a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 9 Feb 2017 13:27:45 +0100 Subject: [PATCH 05/40] Further stuff. --- CMakeLists.txt | 1 + GPU/D3D11/D3D11Util.cpp | 4 ++++ GPU/D3D11/FramebufferManagerD3D11.cpp | 9 +++++++++ GPU/D3D11/FramebufferManagerD3D11.h | 1 + GPU/D3D11/TextureCacheD3D11.cpp | 2 +- ext/native/thin3d/thin3d_vulkan.cpp | 2 +- 6 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2143496ed..4776215820 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1167,6 +1167,7 @@ set(GPU_D3D11 GPU/D3D11/FramebufferManagerD3D11.h GPU/D3D11/GPU_D3D11.cpp GPU/D3D11/GPU_D3D11.h + GPU/D3D11/StencilBufferD3D11.cpp GPU/D3D11/ShaderManagerD3D11.cpp GPU/D3D11/ShaderManagerD3D11.h GPU/D3D11/StateMappingD3D11.cpp diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index ca7e98be32..9a9f48b181 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -59,6 +59,10 @@ void StockObjectsD3D11::Create(ID3D11Device *device) { 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; device->CreateDepthStencilState(&depth_desc, &depthDisabledStencilWrite); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 2cb9ed711b..79f26e1b25 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -119,6 +119,7 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) } FramebufferManagerD3D11::~FramebufferManagerD3D11() { + // Drawing cleanup if (pFramebufferVertexShader_) { pFramebufferVertexShader_->Release(); pFramebufferVertexShader_ = nullptr; @@ -131,10 +132,18 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() { if (drawPixelsTex_) { drawPixelsTex_->Release(); } + + // FBO cleanup for (auto it = tempFBOs_.begin(), end = tempFBOs_.end(); it != end; ++it) { delete it->second.fbo; } delete[] convBuf; + + // Stencil cleanup + for (int i = 0; i < 256; i++) { + if (stencilMaskStates_[i]) + stencilMaskStates_[i]->Release(); + } if (stencilUploadPS_) { stencilUploadPS_->Release(); } diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index f057f99b1a..a9cf0b91df 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -120,6 +120,7 @@ private: ID3D11PixelShader *stencilUploadPS_; ID3D11VertexShader *stencilUploadVS_; ID3D11InputLayout *stencilUploadInputLayout_; + ID3D11DepthStencilState *stencilMaskStates_[256]{}; bool stencilUploadFailed_; TextureCacheD3D11 *textureCacheD3D11_; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index fe54b64039..df1c60baba 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -1157,7 +1157,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & pixelData = (u32 *)map.pData; // We always end up at 8888. Other parts assume this. - assert(dstFmt == D3DFMT_A8R8G8B8); + assert(dstFmt == DXGI_FORMAT_R8G8B8A8_UNORM); bpp = sizeof(u32); decPitch = w * bpp; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 5563f36453..c57058cec8 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -903,7 +903,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { return nullptr; } if (desc.uniformDesc) { - pipeline->dynamicUniformSize = desc.uniformDesc->uniformBufferSize; + pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize; } return pipeline; From 01f46e7a5d8684dd4b7a4ca765c636b2c032e02a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 9 Feb 2017 13:57:24 +0100 Subject: [PATCH 06/40] Make the first generated D3D11 shaders compile, fix various warnings --- GPU/Common/ShaderUniforms.h | 61 ++++++++++++----------- GPU/D3D11/D3D11Util.cpp | 7 ++- GPU/D3D11/D3D11Util.h | 1 + GPU/D3D11/DepalettizeShaderD3D11.cpp | 8 ++- GPU/D3D11/DrawEngineD3D11.cpp | 14 +++++- GPU/D3D11/FramebufferManagerD3D11.cpp | 5 ++ GPU/D3D11/TextureCacheD3D11.cpp | 1 + GPU/Directx9/PixelShaderGeneratorDX9.cpp | 2 +- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 9 ++-- 9 files changed, 69 insertions(+), 39 deletions(-) diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index f58e795ba1..afceaee4ca 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -60,24 +60,25 @@ R"( mat4 proj_mtx; vec2 texclampoff; )"; +// HLSL code is shared so these names are changed to match those in DX9. static const char *cb_baseStr = -R"( matrix proj_mtx; - matrix proj_through_mtx; - matrix view_mtx; - matrix world_mtx; - matrix tex_mtx; - float4 uvscaleoffset; - float4 depthRange; - float3 fogcoef_stencilreplace; - float4 matambientalpha; - float3 fogcolor; - float3 texenv; - ifloat4 alphacolorref; - ifloat4 alphacolormask; - float3 blendFixA; - float3 blendFixB; - float4 texclamp; - float2 texclampoff; +R"( float4x4 u_proj; + float4x4 u_proj_through; + float4x4 u_view; + float4x4 u_world; + float4x4 u_tex; + float4 u_uvscaleoffset; + float4 u_depthRange; + float3 u_fogcoef_stencilreplace; + float4 u_matambientalpha; + float3 u_fogcolor; + float3 u_texenv; + uint4 u_alphacolorref; + uint4 u_alphacolormask; + float3 u_blendFixA; + float3 u_blendFixB; + float4 u_texclamp; + float2 u_texclampoff; )"; // 576 bytes. Can we get down to 512? @@ -111,19 +112,20 @@ R"( vec4 globalAmbient; vec3 specular[4]; )"; +// HLSL code is shared so these names are changed to match those in DX9. static const char *cb_vs_lightsStr = R"( float4 globalAmbient; - float3 matdiffuse; - float4 matspecular; - float3 matemissive; - float3 pos[4]; - float3 dir[4]; - float3 att[4]; - float angle[4]; - float spotCoef[4]; - float3 ambient[4]; - float3 diffuse[4]; - float3 specular[4]; + float3 u_matdiffuse; + float4 u_matspecular; + float3 u_matemissive; + float3 u_lightpos[4]; + float3 u_lightdir[4]; + float3 u_lightatt[4]; + float u_lightangle[4]; + float u_lightspotCoef[4]; + float3 u_ambient[4]; + float3 u_diffuse[4]; + float3 u_specular[4]; )"; // With some cleverness, we could get away with uploading just half this when only the four first @@ -137,8 +139,9 @@ static const char *ub_vs_bonesStr = R"( mat4 m[8]; )"; +// HLSL code is shared so these names are changed to match those in DX9. static const char *cb_vs_bonesStr = -R"( matrix m[8]; +R"( float4x4 m[8]; )"; void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms); diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index 9a9f48b181..2760b786bf 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -11,9 +11,10 @@ static std::vector CompileShaderToBytecode(const char *code, size_t cod ID3DBlob *compiledCode = nullptr; ID3DBlob *errorMsgs = nullptr; HRESULT result = ptr_D3DCompile(code, codeSize, nullptr, nullptr, nullptr, "main", target, 0, 0, &compiledCode, &errorMsgs); + std::string errors; if (errorMsgs) { - std::string errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); - ELOG("%s: %s\n%s", SUCCEEDED(result) ? "warnings" : "errors", code, errors.c_str()); + errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); + ELOG("%s: %s\n%s", SUCCEEDED(result) ? "warnings" : "errors", errors.c_str(), code); errorMsgs->Release(); } if (compiledCode) { @@ -22,6 +23,7 @@ static std::vector CompileShaderToBytecode(const char *code, size_t cod compiledCode->Release(); return compiled; } + Crash(); return std::vector(); } @@ -53,6 +55,7 @@ void StockObjectsD3D11::Create(ID3D11Device *device) { device->CreateBlendState(&blend_desc, &blendStateDisabledWithColorMask[i]); } D3D11_DEPTH_STENCIL_DESC depth_desc{}; + depth_desc.DepthEnable = FALSE; device->CreateDepthStencilState(&depth_desc, &depthStencilDisabled); depth_desc.StencilEnable = TRUE; depth_desc.StencilReadMask = 0xFF; diff --git a/GPU/D3D11/D3D11Util.h b/GPU/D3D11/D3D11Util.h index 7e220e8958..7256a4df2c 100644 --- a/GPU/D3D11/D3D11Util.h +++ b/GPU/D3D11/D3D11Util.h @@ -30,6 +30,7 @@ public: desc.Usage = D3D11_USAGE_DYNAMIC; device->CreateBuffer(&desc, nullptr, &buffer_); } + PushBufferD3D11(PushBufferD3D11 &) = delete; ~PushBufferD3D11() { buffer_->Release(); } diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp index cf88bf78fc..3c8c143469 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.cpp +++ b/GPU/D3D11/DepalettizeShaderD3D11.cpp @@ -101,8 +101,11 @@ ID3D11ShaderResourceView *DepalShaderCacheD3D11::GetClutTexture(GEPaletteFormat desc.Width = texturePixels; desc.Height = 1; desc.ArraySize = 1; + desc.MipLevels = 1; desc.Format = dstFmt; + desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_IMMUTABLE; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; D3D11_SUBRESOURCE_DATA data{}; data.pSysMem = rawClut; @@ -114,7 +117,10 @@ ID3D11ShaderResourceView *DepalShaderCacheD3D11::GetClutTexture(GEPaletteFormat delete tex; return nullptr; } - device_->CreateShaderResourceView(tex->texture, nullptr, &tex->view); + hr = device_->CreateShaderResourceView(tex->texture, nullptr, &tex->view); + if (FAILED(hr)) { + // ... + } tex->lastFrame = gpuStats.numFlips; texCache_[realClutID] = tex; return tex->view; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index b4a003f504..50281dda6d 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -57,6 +57,10 @@ enum { #define VERTEXCACHE_DECIMATION_INTERVAL 17 enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 }; +enum { + VERTEX_PUSH_SIZE = 1024 * 1024 * 16, + INDEX_PUSH_SIZE = 1024 * 1024 * 4, +}; static const D3D11_INPUT_ELEMENT_DESC TransformedVertexElements[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, @@ -99,9 +103,16 @@ DrawEngineD3D11::DrawEngineD3D11(ID3D11Device *device, ID3D11DeviceContext *cont tessDataTransfer = new TessellationDataTransferD3D11(); transformedVertexDecl_ = nullptr; + + // Vertex pushing buffers. + pushVerts_ = new PushBufferD3D11(device, VERTEX_PUSH_SIZE, D3D11_BIND_VERTEX_BUFFER); + pushInds_ = new PushBufferD3D11(device, INDEX_PUSH_SIZE, D3D11_BIND_INDEX_BUFFER); } DrawEngineD3D11::~DrawEngineD3D11() { + delete pushVerts_; + delete pushInds_; + if (transformedVertexDecl_) { transformedVertexDecl_->Release(); } @@ -837,7 +848,8 @@ rotateVBO: ID3D11Buffer *pushVertData = pushVerts_->Buf(); ID3D11Buffer *pushIndexData = pushInds_->Buf(); UINT strides = sizeof(TransformedVertex); - context_->IASetVertexBuffers(0, 1, &pushVertData, &strides, nullptr); + UINT offsets = 0; + context_->IASetVertexBuffers(0, 1, &pushVertData, &strides, &offsets); if (drawIndexed) { context_->IASetIndexBuffer(pushIndexData, DXGI_FORMAT_R16_UINT, 0); context_->DrawIndexed(numTrans, 0, 0); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 79f26e1b25..69070ddbda 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -173,6 +173,11 @@ void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferForm desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; desc.Width = width; desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.SampleDesc.Count = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; device_->CreateTexture2D(&desc, nullptr, &drawPixelsTex_); device_->CreateShaderResourceView(drawPixelsTex_, nullptr, &drawPixelsTexView_); drawPixelsTexW_ = width; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index df1c60baba..8b7885abcf 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -1107,6 +1107,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; desc.Usage = D3D11_USAGE_DYNAMIC; desc.ArraySize = 1; + desc.SampleDesc.Count = 1; desc.Width = tw; desc.Height = th; desc.MipLevels = levels; diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/PixelShaderGeneratorDX9.cpp index e63d362229..29dca6be7c 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/PixelShaderGeneratorDX9.cpp @@ -105,7 +105,7 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage WRITE(p, "float3 u_fogcolor : register(c%i);\n", CONST_PS_FOGCOLOR); } } else { - WRITE(p, "cbuffer base : register(b0) %s;\n", cb_baseStr); + WRITE(p, "cbuffer base : register(b0) {\n%s};\n", cb_baseStr); } if (enableAlphaTest) { diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index f2ddcac446..7d8bda2170 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -104,9 +104,8 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l numBoneWeights = 1 + id.Bits(VS_BIT_BONES, 3); } - WRITE(p, "#pragma warning( disable : 3571 )\n"); - if (lang == HLSL_DX9) { + WRITE(p, "#pragma warning( disable : 3571 )\n"); if (isModeThrough) { WRITE(p, "float4x4 u_proj_through : register(c%i);\n", CONST_VS_PROJ_THROUGH); } else { @@ -177,9 +176,9 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l WRITE(p, "float4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE); } } else { - WRITE(p, "cbuffer base : register(b0) %s;\n", cb_baseStr); - WRITE(p, "cbuffer lights: register(b1) %s;\n", cb_vs_lightsStr); - WRITE(p, "cbuffer bones : register(b2) %s;\n", cb_vs_bonesStr); + WRITE(p, "cbuffer base : register(b0) {\n%s};\n", cb_baseStr); + WRITE(p, "cbuffer lights: register(b1) {\n%s};\n", cb_vs_lightsStr); + WRITE(p, "cbuffer bones : register(b2) {\n%s};\n", cb_vs_bonesStr); } // And the "varyings". From 6b193e74347dc98c99ec1c5c227e7f5e7966e62c Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 10 Feb 2017 00:01:34 +0100 Subject: [PATCH 07/40] Break on D3D11 validation errors in _DEBUG mode --- Windows/GPU/D3D11Context.cpp | 22 ++++++++++++++++++++++ Windows/GPU/D3D11Context.h | 10 +++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index 6c09cfb67d..ad6ef6c90f 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -22,6 +22,9 @@ D3D11Context::~D3D11Context() { void D3D11Context::SwapBuffers() { draw_->HandleEvent(Draw::Event::PRESENT_REQUESTED); + // Might be a good idea. + // context_->ClearState(); + // } void D3D11Context::SwapInterval(int interval) { @@ -70,6 +73,19 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { if (FAILED(hr)) return false; +#ifdef _DEBUG + if (SUCCEEDED(device_->QueryInterface(__uuidof(ID3D11Debug), (void**)&d3dDebug_))) + { + ID3D11InfoQueue *d3dInfoQueue = nullptr; + if (SUCCEEDED(d3dDebug_->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&d3dInfoQueue))) + { + d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); + d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); + d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true); + } + } +#endif + draw_ = Draw::T3DCreateD3D11Context(device_, context_, hWnd_); return true; } @@ -98,6 +114,12 @@ void D3D11Context::Resize() { } void D3D11Context::Shutdown() { +#ifdef _DEBUG + d3dDebug_->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL); +#endif + context_->Flush(); + context_->ClearState(); + delete draw_; draw_ = nullptr; diff --git a/Windows/GPU/D3D11Context.h b/Windows/GPU/D3D11Context.h index 7139ece4d6..927394c3c6 100644 --- a/Windows/GPU/D3D11Context.h +++ b/Windows/GPU/D3D11Context.h @@ -39,9 +39,13 @@ public: Draw::DrawContext *GetDrawContext() override { return draw_; } private: - Draw::DrawContext *draw_; - ID3D11Device *device_; - ID3D11DeviceContext *context_; + Draw::DrawContext *draw_ = nullptr; + ID3D11Device *device_ = nullptr; + ID3D11DeviceContext *context_ = nullptr; + +#ifdef _DEBUG + ID3D11Debug *d3dDebug_ = nullptr; +#endif D3D_DRIVER_TYPE driverType_; D3D_FEATURE_LEVEL featureLevel_ = D3D_FEATURE_LEVEL_11_0; From f9b840dbfdcb45c9d3126f270f427fb4d8c8692a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 10 Feb 2017 00:01:56 +0100 Subject: [PATCH 08/40] More D3D11 progress --- GPU/D3D11/D3D11Util.cpp | 5 +++- GPU/D3D11/DepalettizeShaderD3D11.cpp | 4 ++-- GPU/D3D11/DrawEngineD3D11.cpp | 10 ++++++-- GPU/D3D11/FramebufferManagerD3D11.cpp | 2 +- GPU/D3D11/ShaderManagerD3D11.cpp | 19 ++++++--------- GPU/D3D11/ShaderManagerD3D11.h | 3 ++- GPU/D3D11/StateMappingD3D11.cpp | 11 +++++---- GPU/Directx9/PixelShaderGeneratorDX9.cpp | 16 ++++++++++--- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 28 ++++++++++++++++------- ext/native/base/stringutil.cpp | 13 +++++++++++ ext/native/base/stringutil.h | 3 +++ 11 files changed, 79 insertions(+), 35 deletions(-) diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index 2760b786bf..10766491c9 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -2,8 +2,10 @@ #include #include #include + #include "thin3d/d3d11_loader.h" #include "base/logging.h" +#include "base/stringutil.h" #include "D3D11Util.h" @@ -14,7 +16,8 @@ static std::vector CompileShaderToBytecode(const char *code, size_t cod std::string errors; if (errorMsgs) { errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); - ELOG("%s: %s\n%s", SUCCEEDED(result) ? "warnings" : "errors", errors.c_str(), code); + ELOG("%s: %s", SUCCEEDED(result) ? "warnings" : "errors", errors.c_str()); + OutputDebugStringA(LineNumberString(code).c_str()); errorMsgs->Release(); } if (compiledCode) { diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp index 3c8c143469..b524922d37 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.cpp +++ b/GPU/D3D11/DepalettizeShaderD3D11.cpp @@ -40,8 +40,8 @@ static const char *depalVShaderHLSL = " float2 a_texcoord0 : TEXCOORD0;\n" "};\n" "struct VS_OUT {\n" -" float4 Position : SV_Position;\n" " float2 Texcoord : TEXCOORD0;\n" +" float4 Position : SV_Position;\n" "};\n" "VS_OUT main(VS_IN input) {\n" " VS_OUT output;\n" @@ -66,7 +66,7 @@ DepalShaderCacheD3D11::DepalShaderCacheD3D11(ID3D11Device *device, ID3D11DeviceC sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.Filter = D3D11_FILTER_MINIMUM_MIN_MAG_MIP_POINT; + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; device_->CreateSamplerState(&sampDesc, &clutSampler); } diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 50281dda6d..9db91ee6ea 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -677,13 +677,13 @@ void DrawEngineD3D11::DoFlush() { // TODO: Combine these two into one buffer? void * pVb; u32 size = dec_->GetDecVtxFmt().stride * indexGen.MaxIndex(); - D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_VERTEX_BUFFER, D3D11_CPU_ACCESS_WRITE }; + D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_VERTEX_BUFFER, 0 }; D3D11_SUBRESOURCE_DATA data{ decoded }; device_->CreateBuffer(&desc, &data, &vai->vbo); if (useElements) { void * pIb; u32 size = sizeof(short) * indexGen.VertexCount(); - D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_INDEX_BUFFER, D3D11_CPU_ACCESS_WRITE }; + D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_INDEX_BUFFER, 0 }; D3D11_SUBRESOURCE_DATA data{ decoded }; device_->CreateBuffer(&desc, &data, &vai->ebo); } else { @@ -763,6 +763,8 @@ rotateVBO: D3D11FragmentShader *fshader; shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform); ID3D11InputLayout *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); + context_->PSSetShader(fshader->GetShader(), nullptr, 0); + context_->VSSetShader(vshader->GetShader(), nullptr, 0); context_->IASetInputLayout(pHardwareVertexDecl); if (!vb_) { @@ -829,6 +831,10 @@ rotateVBO: D3D11VertexShader *vshader; D3D11FragmentShader *fshader; shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false); + context_->PSSetShader(fshader->GetShader(), nullptr, 0); + context_->VSSetShader(vshader->GetShader(), nullptr, 0); + shaderManager_->UpdateUniforms(); + shaderManager_->BindUniforms(); // TODO: Implement clear properly when possible. Colormask no longer applies to clearing unfortunately (though wonder if it ever did in hardware..) which makes it trickier. if (result.action == SW_DRAW_PRIMITIVES || result.action == SW_CLEAR) { diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 69070ddbda..c52a22ea7a 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -49,8 +49,8 @@ static const char * vscode = " float2 Uv : TEXCOORD0;\n" "};" "struct VS_OUT {\n" - " float4 ProjPos : SV_Position;\n" " float2 Uv : TEXCOORD0;\n" + " float4 ProjPos : SV_Position;\n" "};\n" "VS_OUT main(VS_IN In) {\n" " VS_OUT Out;\n" diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index 25d45f6ea8..fe631c97c8 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -15,10 +15,6 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#ifdef _WIN32 -#define SHADERLOG -#endif - #include #include @@ -45,10 +41,6 @@ D3D11FragmentShader::D3D11FragmentShader(ID3D11Device *device, ShaderID id, cons : device_(device), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(0) { source_ = code; -#ifdef SHADERLOG - OutputDebugStringA(code); -#endif - module_ = CreatePixelShaderD3D11(device, code, strlen(code)); if (!module_) failed_ = true; @@ -74,10 +66,6 @@ D3D11VertexShader::D3D11VertexShader(ID3D11Device *device, ShaderID id, const ch : device_(device), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(nullptr), usesLighting_(usesLighting) { source_ = code; -#ifdef SHADERLOG - OutputDebugStringA(code); -#endif - module_ = CreateVertexShaderD3D11(device, code, strlen(code), &bytecode_); if (!module_) failed_ = true; @@ -182,6 +170,13 @@ uint64_t ShaderManagerD3D11::UpdateUniforms() { return dirty; } +void ShaderManagerD3D11::BindUniforms() { + ID3D11Buffer *vs_cbs[3] = { push_base, push_lights, push_bones }; + ID3D11Buffer *ps_cbs[1] = { push_base }; + context_->VSSetConstantBuffers(0, 3, vs_cbs); + context_->PSSetConstantBuffers(0, 1, ps_cbs); +} + void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, bool useHWTransform) { ShaderID VSID; ShaderID FSID; diff --git a/GPU/D3D11/ShaderManagerD3D11.h b/GPU/D3D11/ShaderManagerD3D11.h index b7cbbbe24c..aaface9dd9 100644 --- a/GPU/D3D11/ShaderManagerD3D11.h +++ b/GPU/D3D11/ShaderManagerD3D11.h @@ -73,7 +73,7 @@ public: } std::string GetShaderString(DebugShaderStringType type) const; - ID3D11VertexShader *GetModule() const { return module_; } + ID3D11VertexShader *GetShader() const { return module_; } protected: ID3D11VertexShader *module_; @@ -107,6 +107,7 @@ public: std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType); uint64_t UpdateUniforms(); + void BindUniforms(); // TODO: Avoid copying these buffers if same as last draw, can still point to it assuming we're still in the same pushbuffer. // Applies dirty changes and copies the buffer. diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index fa3693a5aa..edf023ae92 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -153,9 +153,9 @@ struct D3D11DepthStencilKey { // Depth/Stencil unsigned int depthTestEnable : 1; unsigned int depthWriteEnable : 1; - unsigned int depthCompareOp : 3; // D3D11_COMPARISON + unsigned int depthCompareOp : 4; // D3D11_COMPARISON (-1 and we could fit it in 3 bits) unsigned int stencilTestEnable : 1; - unsigned int stencilCompareOp : 3; // D3D11_COMPARISON + unsigned int stencilCompareOp : 4; // D3D11_COMPARISON unsigned int stencilPassOp : 4; // D3D11_STENCIL_OP unsigned int stencilFailOp : 4; // D3D11_STENCIL_OP unsigned int stencilDepthFailOp : 4; // D3D11_STENCIL_OP @@ -419,7 +419,9 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { D3D11_DEPTH_STENCIL_DESC desc{}; desc.DepthEnable = keys.depthStencil.depthTestEnable; desc.DepthWriteMask = keys.depthStencil.depthWriteEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - desc.StencilEnable = keys.depthStencil.stencilTestEnable; + desc.DepthFunc = (D3D11_COMPARISON_FUNC)keys.depthStencil.depthCompareOp; + desc.StencilEnable = FALSE; // keys.depthStencil.stencilTestEnable; + // ... device_->CreateDepthStencilState(&desc, &ds); depthStencilCache_.insert(std::pair(depthKey, ds)); @@ -434,7 +436,6 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef) { if (applyStencilRef) { - ID3D11DepthStencilState *state; - context_->OMSetDepthStencilState(state, stencilRef); + // context_->OMSetDepthStencilState(state, stencilRef); } } \ No newline at end of file diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/PixelShaderGeneratorDX9.cpp index 29dca6be7c..382bf440c1 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/PixelShaderGeneratorDX9.cpp @@ -105,6 +105,8 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage WRITE(p, "float3 u_fogcolor : register(c%i);\n", CONST_PS_FOGCOLOR); } } else { + WRITE(p, "SamplerState samp : register(s0);\n"); + WRITE(p, "Texture2D tex : register(t0);\n"); WRITE(p, "cbuffer base : register(b0) {\n%s};\n", cb_baseStr); } @@ -183,10 +185,18 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage doTextureProjection = false; } - if (doTextureProjection) { - WRITE(p, " float4 t = tex2Dproj(tex, float4(In.v_texcoord.x, In.v_texcoord.y, 0, In.v_texcoord.z))%s;\n", bgraTexture ? ".bgra" : ""); + if (lang == HLSL_D3D11) { + if (doTextureProjection) { + WRITE(p, " float4 t = tex.Sample(samp, In.v_texcoord.xy / In.v_texcoord.z)%s;\n", bgraTexture ? ".bgra" : ""); + } else { + WRITE(p, " float4 t = tex.Sample(samp, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : ""); + } } else { - WRITE(p, " float4 t = tex2D(tex, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : ""); + if (doTextureProjection) { + WRITE(p, " float4 t = tex2Dproj(tex, float4(In.v_texcoord.x, In.v_texcoord.y, 0, In.v_texcoord.z))%s;\n", bgraTexture ? ".bgra" : ""); + } else { + WRITE(p, " float4 t = tex2D(tex, %s.xy)%s;\n", texcoord, bgraTexture ? ".bgra" : ""); + } } WRITE(p, " float4 p = In.v_color0;\n"); diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 7d8bda2170..7293f88ea1 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -222,11 +222,6 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l } WRITE(p, "struct VS_OUT {\n"); - if (lang == HLSL_DX9) { - WRITE(p, " float4 gl_Position : POSITION;\n"); - } else { - WRITE(p, " float4 gl_Position : SV_Position;\n"); - } if (doTexture) { WRITE(p, " float3 v_texcoord : TEXCOORD0;\n"); } @@ -237,6 +232,11 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l if (enableFog) { WRITE(p, " float2 v_fogdepth: TEXCOORD1;\n"); } + if (lang == HLSL_DX9) { + WRITE(p, " float4 gl_Position : POSITION;\n"); + } else { + WRITE(p, " float4 gl_Position : SV_Position;\n"); + } WRITE(p, "};\n"); // Confirmed: Through mode gets through exactly the same in GL and D3D in Phantasy Star: Text is 38023.0 in the test scene. @@ -289,7 +289,11 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l // Step 1: World Transform / Skinning if (!enableBones) { // No skinning, just standard T&L. - WRITE(p, " float3 worldpos = mul(float4(In.position.xyz, 1.0), u_world);\n"); + if (lang == HLSL_D3D11) { + WRITE(p, " float3 worldpos = mul(float4(In.position.xyz, 1.0), u_world).xyz;\n"); + } else { + WRITE(p, " float3 worldpos = mul(float4(In.position.xyz, 1.0), u_world);\n"); + } if (hasNormal) WRITE(p, " float3 worldnormal = normalize( mul(float4(%sIn.normal, 0.0), u_world));\n", flipNormal ? "-" : ""); else @@ -367,7 +371,11 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l WRITE(p, " float3 worldnormal = normalize(mul(float4(skinnednormal, 0.0), u_world));\n"); } - WRITE(p, " float4 viewPos = float4(mul(float4(worldpos, 1.0), u_view), 1.0);\n"); + if (lang == HLSL_D3D11) { + WRITE(p, " float4 viewPos = mul(float4(worldpos, 1.0), u_view);\n"); + } else { + WRITE(p, " float4 viewPos = float4(mul(float4(worldpos, 1.0), u_view), 1.0);\n"); + } // Final view and projection transforms. if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { @@ -554,7 +562,11 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l break; } // Transform by texture matrix. XYZ as we are doing projection mapping. - WRITE(p, " Out.v_texcoord.xyz = mul(%s,u_texmtx) * float3(u_uvscaleoffset.xy, 1.0);\n", temp_tc.c_str()); + if (lang == HLSL_D3D11) { + WRITE(p, " Out.v_texcoord.xyz = (mul(%s, u_texmtx) * float4(u_uvscaleoffset.xy, 1.0, 0.0)).xyz;\n", temp_tc.c_str()); + } else { + WRITE(p, " Out.v_texcoord.xyz = mul(%s, u_texmtx) * float3(u_uvscaleoffset.xy, 1.0);\n", temp_tc.c_str()); + } } break; diff --git a/ext/native/base/stringutil.cpp b/ext/native/base/stringutil.cpp index d2dc16d22b..4c72959b39 100644 --- a/ext/native/base/stringutil.cpp +++ b/ext/native/base/stringutil.cpp @@ -39,6 +39,19 @@ void OutputDebugStringUTF8(const char *p) { #endif +std::string LineNumberString(const std::string &str) { + std::stringstream input(str); + std::stringstream output; + std::string line; + + int lineNumber = 1; + while (std::getline(input, line)) { + output << std::setw(4) << lineNumber++ << ": " << line << std::endl; + } + + return output.str(); +} + void StringTrimEndNonAlphaNum(char *str) { ssize_t n = strlen(str); while (!isalnum(str[n]) && n >= 0) { diff --git a/ext/native/base/stringutil.h b/ext/native/base/stringutil.h index 34ceb6076d..e001f42532 100644 --- a/ext/native/base/stringutil.h +++ b/ext/native/base/stringutil.h @@ -25,6 +25,9 @@ public: } }; +// Useful for shaders with error messages.. +std::string LineNumberString(const std::string &str); + // Other simple string utilities. inline bool startsWith(const std::string &str, const std::string &what) { From a7ea1697975c647aae421dc5f39613c1187fbaa7 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 10 Feb 2017 00:07:23 +0100 Subject: [PATCH 09/40] cube.elf now runs in D3D11 mode, still blackscreen --- GPU/D3D11/DrawEngineD3D11.cpp | 1 - GPU/D3D11/GPU_D3D11.cpp | 5 +++++ GPU/D3D11/GPU_D3D11.h | 2 ++ GPU/D3D11/TextureCacheD3D11.cpp | 3 +++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 9db91ee6ea..1010375bd1 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -616,7 +616,6 @@ void DrawEngineD3D11::DoFlush() { vai->prim = indexGen.Prim(); vai->maxIndex = indexGen.MaxIndex(); vai->flags = gstate_c.vertexFullAlpha ? VAI11_FLAG_VERTEXFULLALPHA : 0; - goto rotateVBO; } diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 5bccb87d3f..d915a5b155 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -564,6 +564,11 @@ void GPU_D3D11::ReapplyGfxStateInternal() { // TODO: Dirty our caches for depth states etc } +void GPU_D3D11::EndHostFrame() { + // Tell the DrawContext that it's time to reset everything. + draw_->BindPipeline(nullptr); +} + void GPU_D3D11::BeginFrameInternal() { if (resized_) { UpdateCmdInfo(); diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index 337342f9c7..a618462a57 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -90,6 +90,8 @@ public: std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; + void EndHostFrame() override; + protected: void FastRunLoop(DisplayList &list) override; void FinishDeferred() override; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 8b7885abcf..3344a03daa 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -107,6 +107,9 @@ ID3D11SamplerState *SamplerCacheD3D11::GetOrCreateSampler(ID3D11Device *device, TextureCacheD3D11::TextureCacheD3D11(Draw::DrawContext *draw) : TextureCacheCommon(draw) { + device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE); + context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); + lastBoundTexture = INVALID_TEX; decimationCounter_ = TEXCACHE_DECIMATION_INTERVAL; From aba669c3e607953202cca59bc523d7dd60bfbcb3 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 10 Feb 2017 00:30:42 +0100 Subject: [PATCH 10/40] D3D11: Cube now visible --- GPU/D3D11/StateMappingD3D11.cpp | 18 +++++-- GPU/D3D11/TextureCacheD3D11.cpp | 4 +- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 59 ++++++++++++++++------- Windows/GPU/D3D11Context.cpp | 10 ++-- ext/native/thin3d/thin3d.h | 1 + 5 files changed, 63 insertions(+), 29 deletions(-) diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index edf023ae92..6742dae7a2 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -30,6 +30,7 @@ #include "GPU/Common/FramebufferCommon.h" #include "GPU/D3D11/DrawEngineD3D11.h" #include "GPU/D3D11/FramebufferManagerD3D11.h" +#include "GPU/D3D11/TextureCacheD3D11.h" // These tables all fit into u8s. static const D3D11_BLEND d3d11BlendFactorLookup[(size_t)BlendFactor::COUNT] = { @@ -185,8 +186,6 @@ struct D3D11DynamicState { }; void ConvertStateToKeys(FramebufferManagerCommon *fbManager, ShaderManagerD3D11 *shaderManager, int prim, D3D11StateKeys &key, D3D11DynamicState &dynState) { - memset(&key, 0, sizeof(key)); - memset(&dynState, 0, sizeof(dynState)); // Unfortunately, this isn't implemented yet. gstate_c.allowShaderBlend = false; @@ -383,8 +382,18 @@ void ConvertStateToKeys(FramebufferManagerCommon *fbManager, ShaderManagerD3D11 } void DrawEngineD3D11::ApplyDrawState(int prim) { - D3D11StateKeys keys; - D3D11DynamicState dynState; + if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { + textureCache_->SetTexture(); + gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + if (gstate_c.needShaderTexClamp) { + // We will rarely need to set this, so let's do it every time on use rather than in runloop. + // Most of the time non-framebuffer textures will be used which can be clamped themselves. + gstate_c.Dirty(DIRTY_TEXCLAMP); + } + } + + D3D11StateKeys keys{}; + D3D11DynamicState dynState{}; ConvertStateToKeys(framebufferManager_, shaderManager_, prim, keys, dynState); uint32_t blendKey, depthKey, rasterKey; @@ -435,6 +444,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef) { + textureCache_->ApplyTexture(); if (applyStencilRef) { // context_->OMSetDepthStencilState(state, stencilRef); } diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 3344a03daa..60972a6bf0 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -132,7 +132,7 @@ void TextureCacheD3D11::SetFramebufferManager(FramebufferManagerD3D11 *fbManager } void TextureCacheD3D11::Clear(bool delete_them) { - context_->PSSetShaderResources(0, 1, nullptr); + // context_->PSSetShaderResources(0, 1, nullptr); lastBoundTexture = INVALID_TEX; if (delete_them) { for (TexCache::iterator iter = cache.begin(); iter != cache.end(); ++iter) { @@ -1113,7 +1113,9 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & desc.SampleDesc.Count = 1; desc.Width = tw; desc.Height = th; + desc.Format = tfmt; desc.MipLevels = levels; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; HRESULT hr = device_->CreateTexture2D(&desc, nullptr, &texture); if (FAILED(hr)) { diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 7293f88ea1..15cd493a68 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -276,13 +276,25 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l if (enableFog) { WRITE(p, " Out.v_fogdepth.x = In.position.w;\n"); } - if (gstate.isModeThrough()) { - WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj_through);\n"); - } else { - if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " Out.gl_Position = depthRoundZVP(mul(float4(In.position.xyz, 1.0), u_proj));\n"); + if (lang == HLSL_D3D11) { + if (gstate.isModeThrough()) { + WRITE(p, " Out.gl_Position = mul(u_proj_through, float4(In.position.xyz, 1.0));\n"); } else { - WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj);\n"); + if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + WRITE(p, " Out.gl_Position = depthRoundZVP(mul(u_proj, float4(In.position.xyz, 1.0)));\n"); + } else { + WRITE(p, " Out.gl_Position = mul(u_proj, float4(In.position.xyz, 1.0));\n"); + } + } + } else { + if (gstate.isModeThrough()) { + WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj_through);\n"); + } else { + if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + WRITE(p, " Out.gl_Position = depthRoundZVP(mul(float4(In.position.xyz, 1.0), u_proj));\n"); + } else { + WRITE(p, " Out.gl_Position = mul(float4(In.position.xyz, 1.0), u_proj);\n"); + } } } } else { @@ -290,14 +302,18 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l if (!enableBones) { // No skinning, just standard T&L. if (lang == HLSL_D3D11) { - WRITE(p, " float3 worldpos = mul(float4(In.position.xyz, 1.0), u_world).xyz;\n"); + WRITE(p, " float3 worldpos = mul(u_world, float4(In.position.xyz, 1.0)).xyz;\n"); + if (hasNormal) + WRITE(p, " float3 worldnormal = normalize( mul(u_world, float4(%sIn.normal, 0.0)));\n", flipNormal ? "-" : ""); + else + WRITE(p, " float3 worldnormal = float3(0.0, 0.0, 1.0);\n"); } else { WRITE(p, " float3 worldpos = mul(float4(In.position.xyz, 1.0), u_world);\n"); + if (hasNormal) + WRITE(p, " float3 worldnormal = normalize( mul(float4(%sIn.normal, 0.0), u_world));\n", flipNormal ? "-" : ""); + else + WRITE(p, " float3 worldnormal = float3(0.0, 0.0, 1.0);\n"); } - if (hasNormal) - WRITE(p, " float3 worldnormal = normalize( mul(float4(%sIn.normal, 0.0), u_world));\n", flipNormal ? "-" : ""); - else - WRITE(p, " float3 worldnormal = float3(0.0, 0.0, 1.0);\n"); } else { static const char * const boneWeightAttr[8] = { "a_w1.x", "a_w1.y", "a_w1.z", "a_w1.w", @@ -372,16 +388,23 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l } if (lang == HLSL_D3D11) { - WRITE(p, " float4 viewPos = mul(float4(worldpos, 1.0), u_view);\n"); + WRITE(p, " float4 viewPos = mul(u_view, float4(worldpos, 1.0));\n"); + + // Final view and projection transforms. + if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + WRITE(p, " Out.gl_Position = depthRoundZVP(mul(u_proj, viewPos));\n"); + } else { + WRITE(p, " Out.gl_Position = mul(u_proj, viewPos);\n"); + } } else { WRITE(p, " float4 viewPos = float4(mul(float4(worldpos, 1.0), u_view), 1.0);\n"); - } - // Final view and projection transforms. - if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " Out.gl_Position = depthRoundZVP(mul(viewPos, u_proj));\n"); - } else { - WRITE(p, " Out.gl_Position = mul(viewPos, u_proj);\n"); + // Final view and projection transforms. + if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { + WRITE(p, " Out.gl_Position = depthRoundZVP(mul(viewPos, u_proj));\n"); + } else { + WRITE(p, " Out.gl_Position = mul(viewPos, u_proj);\n"); + } } // TODO: Declare variables for dots for shade mapping if needed. diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index ad6ef6c90f..c0288a6ada 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -74,11 +74,9 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { return false; #ifdef _DEBUG - if (SUCCEEDED(device_->QueryInterface(__uuidof(ID3D11Debug), (void**)&d3dDebug_))) - { + if (SUCCEEDED(device_->QueryInterface(__uuidof(ID3D11Debug), (void**)&d3dDebug_))) { ID3D11InfoQueue *d3dInfoQueue = nullptr; - if (SUCCEEDED(d3dDebug_->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&d3dInfoQueue))) - { + if (SUCCEEDED(d3dDebug_->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&d3dInfoQueue))) { d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true); @@ -92,6 +90,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { void D3D11Context::Resize() { draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER); + draw_->HandleEvent(Draw::Event::RESIZED); // This should only be called from the emu thread. /* int xres, yres; @@ -99,12 +98,11 @@ void D3D11Context::Resize() { bool w_changed = pp.BackBufferWidth != xres; bool h_changed = pp.BackBufferHeight != yres; - if (device && (w_changed || h_changed)) { + if (device_ && (w_changed || h_changed)) { pp.BackBufferWidth = xres; pp.BackBufferHeight = yres; HRESULT hr = device_->Reset(&pp); if (FAILED(hr)) { - // Had to remove DXGetErrorStringA calls here because dxerr.lib is deprecated and will not link with VS 2015. ERROR_LOG_REPORT(G3D, "Unable to reset D3D device"); PanicAlert("Unable to reset D3D11 device"); } diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index d3f49fe2db..f58c618704 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -347,6 +347,7 @@ enum class Event { // These happen on D3D resize LOST_BACKBUFFER, GOT_BACKBUFFER, + RESIZED, PRESENT_REQUESTED, }; From 9a6f3ccfad95357841469676fef1921412572c7a Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 10 Feb 2017 00:37:56 +0100 Subject: [PATCH 11/40] D3D11: Fix depth state --- GPU/D3D11/DrawEngineD3D11.h | 5 ++-- GPU/D3D11/StateMappingD3D11.cpp | 52 +++++++++++++++------------------ 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index 6ccf017085..b8316f7105 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -161,8 +161,6 @@ private: void ApplyDrawState(int prim); void ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef); - bool ApplyShaderBlending(); - void ResetShaderBlending(); ID3D11InputLayout *SetupDecFmtForDraw(D3D11VertexShader *vshader, const DecVtxFormat &decFmt, u32 pspFmt); @@ -231,6 +229,9 @@ private: std::map depthStencilCache_; std::map rasterCache_; + // Keep the depth state between ApplyDrawState and ApplyDrawStateLate + ID3D11DepthStencilState *depthStencilState_; + // Hardware tessellation class TessellationDataTransferD3D11 : public TessellationDataTransfer { private: diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 6742dae7a2..d88285d181 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -185,7 +185,10 @@ struct D3D11DynamicState { D3D11_RECT scissor; }; -void ConvertStateToKeys(FramebufferManagerCommon *fbManager, ShaderManagerD3D11 *shaderManager, int prim, D3D11StateKeys &key, D3D11DynamicState &dynState) { +void DrawEngineD3D11::ApplyDrawState(int prim) { + D3D11StateKeys key{}; + D3D11DynamicState dynState{}; + // Unfortunately, this isn't implemented yet. gstate_c.allowShaderBlend = false; @@ -197,8 +200,8 @@ void ConvertStateToKeys(FramebufferManagerCommon *fbManager, ShaderManagerD3D11 ViewportAndScissor vpAndScissor; ConvertViewportAndScissor(useBufferedRendering, - fbManager->GetRenderWidth(), fbManager->GetRenderHeight(), - fbManager->GetTargetBufferWidth(), fbManager->GetTargetBufferHeight(), + framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(), + framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(), vpAndScissor); if (blendState.applyShaderBlending) { @@ -245,7 +248,7 @@ void ConvertStateToKeys(FramebufferManagerCommon *fbManager, ShaderManagerD3D11 key.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS; key.depthStencil.depthWriteEnable = gstate.isClearModeDepthMask(); if (gstate.isClearModeDepthMask()) { - fbManager->SetDepthUpdated(); + framebufferManager_->SetDepthUpdated(); } // Color Test @@ -291,7 +294,7 @@ void ConvertStateToKeys(FramebufferManagerCommon *fbManager, ShaderManagerD3D11 key.depthStencil.depthCompareOp = compareOps[gstate.getDepthTestFunction()]; key.depthStencil.depthWriteEnable = gstate.isDepthWriteEnabled(); if (gstate.isDepthWriteEnabled()) { - fbManager->SetDepthUpdated(); + framebufferManager_->SetDepthUpdated(); } } else { key.depthStencil.depthTestEnable = false; @@ -379,9 +382,7 @@ void ConvertStateToKeys(FramebufferManagerCommon *fbManager, ShaderManagerD3D11 if (vpAndScissor.dirtyDepth) { gstate_c.Dirty(DIRTY_DEPTHRANGE); } -} -void DrawEngineD3D11::ApplyDrawState(int prim) { if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); @@ -392,14 +393,10 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } } - D3D11StateKeys keys{}; - D3D11DynamicState dynState{}; - ConvertStateToKeys(framebufferManager_, shaderManager_, prim, keys, dynState); - uint32_t blendKey, depthKey, rasterKey; - memcpy(&blendKey, &keys.blend, sizeof(uint32_t)); - memcpy(&depthKey, &keys.depthStencil, sizeof(uint32_t)); - memcpy(&rasterKey, &keys.raster, sizeof(uint32_t)); + memcpy(&blendKey, &key.blend, sizeof(uint32_t)); + memcpy(&depthKey, &key.depthStencil, sizeof(uint32_t)); + memcpy(&rasterKey, &key.raster, sizeof(uint32_t)); ID3D11BlendState *bs = nullptr; ID3D11DepthStencilState *ds = nullptr; @@ -409,14 +406,14 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { if (blendIter == blendCache_.end()) { D3D11_BLEND_DESC desc{}; D3D11_RENDER_TARGET_BLEND_DESC &rt = desc.RenderTarget[0]; - 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; + 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; device_->CreateBlendState(&desc, &bs); blendCache_.insert(std::pair(blendKey, bs)); } else { @@ -426,9 +423,9 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { auto depthIter = depthStencilCache_.find(depthKey); if (depthIter == depthStencilCache_.end()) { D3D11_DEPTH_STENCIL_DESC desc{}; - 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.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 = FALSE; // keys.depthStencil.stencilTestEnable; // ... @@ -437,6 +434,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } else { ds = depthIter->second; } + depthStencilState_ = ds; float blendColor[4]; Uint8x4ToFloat4(blendColor, dynState.blendColor); @@ -445,7 +443,5 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef) { textureCache_->ApplyTexture(); - if (applyStencilRef) { - // context_->OMSetDepthStencilState(state, stencilRef); - } + context_->OMSetDepthStencilState(depthStencilState_, applyStencilRef ? stencilRef : 0xFF); } \ No newline at end of file From 5ee3b534ed632421edf4ba1e3006bc4120110d20 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 10 Feb 2017 10:26:18 +0100 Subject: [PATCH 12/40] More D3D11 improvements --- GPU/Common/SoftwareTransformCommon.cpp | 2 +- GPU/D3D11/D3D11Util.h | 4 +- GPU/D3D11/DrawEngineD3D11.cpp | 123 +++++++++++++++---------- GPU/D3D11/DrawEngineD3D11.h | 21 ++++- GPU/D3D11/GPU_D3D11.cpp | 5 +- GPU/D3D11/TextureCacheD3D11.cpp | 3 +- UI/GameSettingsScreen.cpp | 4 +- Windows/GPU/D3D11Context.cpp | 2 +- ext/native/thin3d/thin3d_d3d11.cpp | 14 ++- 9 files changed, 114 insertions(+), 64 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 5a1bfc4955..5d9c2cf4c7 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -406,7 +406,7 @@ void SoftwareTransform( int scissorY2 = gstate.getScissorY2() + 1; reallyAClear = IsReallyAClear(transformed, maxIndex, scissorX2, scissorY2); } - if (reallyAClear && gl_extensions.gpuVendor != GPU_VENDOR_POWERVR) { // && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) { + if (reallyAClear && gl_extensions.gpuVendor != GPU_VENDOR_POWERVR) { // If alpha is not allowed to be separate, it must match for both depth/stencil and color. Vulkan requires this. bool alphaMatchesColor = gstate.isClearModeColorMask() == gstate.isClearModeAlphaMask(); bool depthMatchesStencil = gstate.isClearModeAlphaMask() == gstate.isClearModeDepthMask(); diff --git a/GPU/D3D11/D3D11Util.h b/GPU/D3D11/D3D11Util.h index 7256a4df2c..83296a13e6 100644 --- a/GPU/D3D11/D3D11Util.h +++ b/GPU/D3D11/D3D11Util.h @@ -44,11 +44,11 @@ public: nextMapDiscard_ = true; } - uint8_t *BeginPush(ID3D11DeviceContext *context, int &offset, size_t size) { + uint8_t *BeginPush(ID3D11DeviceContext *context, UINT *offset, size_t size) { D3D11_MAPPED_SUBRESOURCE map; context->Map(buffer_, 0, nextMapDiscard_ ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map); nextMapDiscard_ = false; - offset = (int)pos_; + *offset = (UINT)pos_; uint8_t *retval = (uint8_t *)map.pData + pos_; pos_ += size; return retval; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 1010375bd1..d7a79ad5e1 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -69,8 +69,9 @@ static const D3D11_INPUT_ELEMENT_DESC TransformedVertexElements[] = { { "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; -DrawEngineD3D11::DrawEngineD3D11(ID3D11Device *device, ID3D11DeviceContext *context) - : device_(device), +DrawEngineD3D11::DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context) + : draw_(draw), + device_(device), context_(context), decodedVerts_(0), prevPrim_(GE_PRIM_INVALID), @@ -102,7 +103,6 @@ DrawEngineD3D11::DrawEngineD3D11(ID3D11Device *device, ID3D11DeviceContext *cont InitDeviceObjects(); tessDataTransfer = new TessellationDataTransferD3D11(); - transformedVertexDecl_ = nullptr; // Vertex pushing buffers. pushVerts_ = new PushBufferD3D11(device, VERTEX_PUSH_SIZE, D3D11_BIND_VERTEX_BUFFER); @@ -113,8 +113,16 @@ DrawEngineD3D11::~DrawEngineD3D11() { delete pushVerts_; delete pushInds_; - if (transformedVertexDecl_) { - transformedVertexDecl_->Release(); + for (auto decl = inputLayoutMap_.begin(); decl != inputLayoutMap_.end(); ++decl) { + if (decl->second) { + decl->second->Release(); + } + } + for (auto &depth : depthStencilCache_) { + depth.second->Release(); + } + for (auto &blend : blendCache_) { + blend.second->Release(); } DestroyDeviceObjects(); @@ -123,11 +131,6 @@ DrawEngineD3D11::~DrawEngineD3D11() { FreeMemoryPages(splineBuffer, SPLINE_BUFFER_SIZE); FreeMemoryPages(transformed, TRANSFORMED_VERTEX_BUFFER_SIZE); FreeMemoryPages(transformedExpanded, 3 * TRANSFORMED_VERTEX_BUFFER_SIZE); - for (auto decl = vertexDeclMap_.begin(); decl != vertexDeclMap_.end(); ++decl) { - if (decl->second) { - decl->second->Release(); - } - } delete tessDataTransfer; } @@ -177,9 +180,11 @@ static void VertexAttribSetup(D3D11_INPUT_ELEMENT_DESC * VertexElement, u8 fmt, } ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshader, const DecVtxFormat &decFmt, u32 pspFmt) { - auto vertexDeclCached = vertexDeclMap_.find(pspFmt); - - if (vertexDeclCached == vertexDeclMap_.end()) { + // TODO: Instead of one for each vshader, we can reduce it to one for each type of shader + // that reads TEXCOORD or not, etc. Not sure if worth it. + InputLayoutKey key{ pspFmt, vshader }; + auto vertexDeclCached = inputLayoutMap_.find(key); + if (vertexDeclCached == inputLayoutMap_.end()) { D3D11_INPUT_ELEMENT_DESC VertexElements[8]; D3D11_INPUT_ELEMENT_DESC *VertexElement = &VertexElements[0]; @@ -232,7 +237,7 @@ ID3D11InputLayout *DrawEngineD3D11::SetupDecFmtForDraw(D3D11VertexShader *vshade } // Add it to map - vertexDeclMap_[pspFmt] = inputLayout; + inputLayoutMap_[key] = inputLayout; return inputLayout; } else { // Set it from map @@ -512,7 +517,10 @@ void DrawEngineD3D11::ClearTrackedVertexArrays() { vai_.clear(); } -void DrawEngineD3D11::DecimateTrackedVertexArrays() { +void DrawEngineD3D11::BeginFrame() { + pushVerts_->Reset(); + pushInds_->Reset(); + if (--decimationCounter_ <= 0) { decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL; } else { @@ -674,16 +682,14 @@ void DrawEngineD3D11::DoFlush() { _dbg_assert_msg_(G3D, gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching."); // TODO: Combine these two into one buffer? - void * pVb; u32 size = dec_->GetDecVtxFmt().stride * indexGen.MaxIndex(); D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_VERTEX_BUFFER, 0 }; D3D11_SUBRESOURCE_DATA data{ decoded }; device_->CreateBuffer(&desc, &data, &vai->vbo); if (useElements) { - void * pIb; u32 size = sizeof(short) * indexGen.VertexCount(); D3D11_BUFFER_DESC desc{ size, D3D11_USAGE_IMMUTABLE, D3D11_BIND_INDEX_BUFFER, 0 }; - D3D11_SUBRESOURCE_DATA data{ decoded }; + D3D11_SUBRESOURCE_DATA data{ decIndex }; device_->CreateBuffer(&desc, &data, &vai->ebo); } else { vai->ebo = 0; @@ -761,25 +767,38 @@ rotateVBO: D3D11VertexShader *vshader; D3D11FragmentShader *fshader; shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform); - ID3D11InputLayout *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); + ID3D11InputLayout *inputLayout = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); - context_->IASetInputLayout(pHardwareVertexDecl); + context_->IASetInputLayout(inputLayout); + UINT stride = dec_->GetDecVtxFmt().stride; + context_->IASetPrimitiveTopology(glprim[prim]); if (!vb_) { // Push! - int vOffset; - // pushVerts_->BeginPush(context_, offset, ) + UINT vOffset; + int vSize = (maxIndex + 1) * dec_->GetDecVtxFmt().stride; + uint8_t *vptr = pushVerts_->BeginPush(context_, &vOffset, vSize); + memcpy(vptr, decoded, vSize); + pushVerts_->EndPush(context_); + ID3D11Buffer *buf = pushVerts_->Buf(); + context_->IASetVertexBuffers(0, 1, &buf, &stride, &vOffset); if (useElements) { + UINT iOffset; + int iSize = 2 * vertexCount; + uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize); + memcpy(iptr, decIndex, iSize); + pushInds_->EndPush(context_); + context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset); + context_->DrawIndexed(vertexCount, 0, 0); // context_->DrawIndexedPrimitiveUP(glprim[prim], 0, maxIndex + 1, D3DPrimCount(glprim[prim], vertexCount), decIndex, D3DFMT_INDEX16, decoded, dec_->GetDecVtxFmt().stride); } else { // context_->DrawPrimitiveUP(glprim[prim], D3DPrimCount(glprim[prim], vertexCount), decoded, dec_->GetDecVtxFmt().stride); + context_->Draw(vertexCount, 0); } } else { - UINT stride = dec_->GetDecVtxFmt().stride; UINT offset = 0; context_->IASetVertexBuffers(0, 1, &vb_, &stride, &offset); - context_->IASetPrimitiveTopology(glprim[prim]); if (useElements) { context_->IASetIndexBuffer(ib_, DXGI_FORMAT_R16_UINT, 0); context_->DrawIndexed(vertexCount, 0, 0); @@ -835,40 +854,50 @@ rotateVBO: shaderManager_->UpdateUniforms(); shaderManager_->BindUniforms(); - // TODO: Implement clear properly when possible. Colormask no longer applies to clearing unfortunately (though wonder if it ever did in hardware..) which makes it trickier. - if (result.action == SW_DRAW_PRIMITIVES || result.action == SW_CLEAR) { - // TODO: Add a post-transform cache here for multi-RECTANGLES only. - // Might help for text drawing. - - // these spam the gDebugger log. + if (result.action == SW_DRAW_PRIMITIVES) { const int vertexSize = sizeof(transformed[0]); // This is so weird. Why do we need the shader bytecode to create an input layout?? - // Well, at least all vshaders for pretransformed data will have one single layout so we can share it. - if (!transformedVertexDecl_) { - device_->CreateInputLayout(TransformedVertexElements, 4, vshader->bytecode().data(), vshader->bytecode().size(), &transformedVertexDecl_); + // We really do need a vertex layout for each vertex shader (or at least check its ID bits for what inputs it uses)! + // Some vertex shaders ignore one of the inputs, and then the layout created from it will lack it, which will be a problem for others. + InputLayoutKey key{ 0xFFFFFFFF, vshader }; // Let's use 0xFFFFFFFF to signify TransformedVertex + auto iter = inputLayoutMap_.find(key); + ID3D11InputLayout *layout; + if (iter == inputLayoutMap_.end()) { + device_->CreateInputLayout(TransformedVertexElements, ARRAY_SIZE(TransformedVertexElements), vshader->bytecode().data(), vshader->bytecode().size(), &layout); + inputLayoutMap_[key] = layout; + } else { + layout = iter->second; } + context_->IASetInputLayout(layout); - context_->IASetInputLayout(transformedVertexDecl_); - ID3D11Buffer *pushVertData = pushVerts_->Buf(); - ID3D11Buffer *pushIndexData = pushInds_->Buf(); - UINT strides = sizeof(TransformedVertex); - UINT offsets = 0; - context_->IASetVertexBuffers(0, 1, &pushVertData, &strides, &offsets); + UINT stride = sizeof(TransformedVertex); + UINT vOffset = 0; + int vSize = numTrans * dec_->GetDecVtxFmt().stride; + uint8_t *vptr = pushVerts_->BeginPush(context_, &vOffset, vSize); + memcpy(vptr, drawBuffer, vSize); + pushVerts_->EndPush(context_); + ID3D11Buffer *buf = pushVerts_->Buf(); + context_->IASetVertexBuffers(0, 1, &buf, &stride, &vOffset); if (drawIndexed) { - context_->IASetIndexBuffer(pushIndexData, DXGI_FORMAT_R16_UINT, 0); - context_->DrawIndexed(numTrans, 0, 0); + UINT iOffset; + int iSize = 2 * (maxIndex + 1); + uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize); + memcpy(iptr, inds, iSize); + pushInds_->EndPush(context_); + context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset); + context_->DrawIndexed(maxIndex + 1, 0, 0); // context_->DrawIndexedPrimitiveUP(glprim[prim], 0, maxIndex, numTrans, inds, DXGI_FORMAT_R16_UINT, drawBuffer, sizeof(TransformedVertex)); } else { - // context_->DrawPrimitiveUP(glprim[prim], D3DPrimCount(glprim[prim], numTrans), drawBuffer, sizeof(TransformedVertex)); context_->Draw(numTrans, 0); } - } /*else if (result.action == SW_CLEAR) { + } else if (result.action == SW_CLEAR) { u32 clearColor = result.color; float clearDepth = result.depth; UINT depthClearFlag = 0; + /* bool clearColor = gstate.isClearModeColorMask(); if (gstate.isClearModeAlphaMask()) depthClearFlag |= D3D11_CLEAR_STENCIL; if (gstate.isClearModeDepthMask()) depthClearFlag |= D3D11_CLEAR_DEPTH; @@ -889,17 +918,17 @@ rotateVBO: context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[colorMask], nullptr, 0xFFFFFFFF); device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24); + */ - int scissorX1 = gstate.getScissorX1(); - int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; framebufferManager_->SetSafeSize(scissorX2, scissorY2); - if (g_Config.bBlockTransferGPU && (gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { + int scissorX1 = gstate.getScissorX1(); + int scissorY1 = gstate.getScissorY1(); ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } - }*/ + } } gpuStats.numDrawCalls += numDrawCalls; diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index b8316f7105..42effbee24 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -108,7 +108,7 @@ public: // Handles transform, lighting and drawing. class DrawEngineD3D11 : public DrawEngineCommon { public: - DrawEngineD3D11(ID3D11Device *device, ID3D11DeviceContext *context); + DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context); virtual ~DrawEngineD3D11(); void SubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead); @@ -128,7 +128,7 @@ public: void Resized(); // TODO: Call - void DecimateTrackedVertexArrays(); + void BeginFrame(); void ClearTrackedVertexArrays(); void SetupVertexDecoder(u32 vertType); @@ -168,6 +168,7 @@ private: ReliableHashType ComputeHash(); // Reads deferred vertex data. void MarkUnreliable(VertexArrayInfoD3D11 *vai); + Draw::DrawContext *draw_; // Used for framebuffer related things exclusively. ID3D11Device *device_; ID3D11DeviceContext *context_; @@ -195,10 +196,20 @@ private: TransformedVertex *transformedExpanded; std::unordered_map vai_; - std::unordered_map vertexDeclMap_; - // SimpleVertex - ID3D11InputLayout *transformedVertexDecl_; + struct InputLayoutKey { + u32 vertType; + D3D11VertexShader *vshader; + bool operator <(const InputLayoutKey &other) const { + if (vertType < other.vertType) + return true; + if (vertType > other.vertType) + return false; + return vshader < other.vshader; + } + }; + + std::map inputLayoutMap_; // Other ShaderManagerD3D11 *shaderManager_; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index d915a5b155..db05a454c8 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -409,7 +409,7 @@ static const CommandTableEntry commandTable[] = { GPU_D3D11::CommandInfo GPU_D3D11::cmdInfo_[256]; GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) - : GPUCommon(gfxCtx, draw), drawEngine_( + : GPUCommon(gfxCtx, draw), drawEngine_(draw, (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE), (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT)) { device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE); @@ -480,6 +480,7 @@ GPU_D3D11::~GPU_D3D11() { delete depalShaderCache_; framebufferManagerD3D11_->DestroyAllFBOs(true); shaderManagerD3D11_->ClearShaders(); + draw_->BindPipeline(nullptr); delete shaderManagerD3D11_; stockD3D11.Destroy(); } @@ -578,7 +579,7 @@ void GPU_D3D11::BeginFrameInternal() { } textureCacheD3D11_->StartFrame(); - drawEngine_.DecimateTrackedVertexArrays(); + drawEngine_.BeginFrame(); depalShaderCache_->Decimate(); // fragmentTestCache_.Decimate(); diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 60972a6bf0..946bfe3ad5 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -354,7 +354,8 @@ inline u32 TextureCacheD3D11::GetCurrentClutHash() { } void TextureCacheD3D11::Unbind() { - context_->PSSetShaderResources(0, 1, nullptr); + ID3D11ShaderResourceView *nullView = nullptr; + context_->PSSetShaderResources(0, 1, &nullView); } void TextureCacheD3D11::ApplyTexture() { diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 2a202b0914..48c1d09dfb 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -153,14 +153,12 @@ void GameSettingsScreen::CreateViews() { tabHolder->AddTab(ms->T("Graphics"), graphicsSettingsScroll); graphicsSettings->Add(new ItemHeader(gr->T("Rendering Mode"))); - static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan (experimental)" }; + static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11 (experimental)", "Vulkan (experimental)" }; PopupMultiChoice *renderingBackendChoice = graphicsSettings->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, GPU_BACKEND_OPENGL, ARRAY_SIZE(renderingBackend), gr->GetName(), screenManager())); renderingBackendChoice->OnChoice.Handle(this, &GameSettingsScreen::OnRenderingBackend); #if !defined(_WIN32) renderingBackendChoice->HideChoice(1); // D3D9 renderingBackendChoice->HideChoice(2); // D3D11 -#else - // renderingBackendChoice->HideChoice(2); // D3D11 #endif #if !defined(_WIN32) // TODO: Add dynamic runtime check for Vulkan support on Android diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index c0288a6ada..37e497010f 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -115,8 +115,8 @@ void D3D11Context::Shutdown() { #ifdef _DEBUG d3dDebug_->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL); #endif - context_->Flush(); context_->ClearState(); + context_->Flush(); delete draw_; draw_ = nullptr; diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 6550ca8d0f..bffe80e27f 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -130,6 +130,9 @@ private: ID3D11Texture2D *bbDepthStencilTex_ = nullptr; ID3D11DepthStencilView *bbDepthStencilView_ = nullptr; + ID3D11RenderTargetView *curRenderTargetView_ = nullptr; + ID3D11DepthStencilView *curDepthStencilView_ = nullptr; + D3D11Pipeline *curPipeline_; DeviceCaps caps_; @@ -244,6 +247,9 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *co context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_); + curRenderTargetView_ = bbRenderTargetView_; + curDepthStencilView_ = bbDepthStencilView_; + CreatePresets(); } @@ -1099,7 +1105,7 @@ void D3D11DrawContext::Clear(int mask, uint32_t colorval, float depthVal, int st if (mask & ClearFlag::COLOR) { float colorRGBA[4]; Uint8x1ToFloat4(colorRGBA, colorval); - context_->ClearRenderTargetView(bbRenderTargetView_, colorRGBA); + context_->ClearRenderTargetView(curRenderTargetView_, colorRGBA); } if (mask & (ClearFlag::DEPTH | ClearFlag::STENCIL)) { UINT clearFlag = 0; @@ -1107,7 +1113,7 @@ void D3D11DrawContext::Clear(int mask, uint32_t colorval, float depthVal, int st clearFlag |= D3D11_CLEAR_DEPTH; if (mask & ClearFlag::STENCIL) clearFlag |= D3D11_CLEAR_STENCIL; - context_->ClearDepthStencilView(bbDepthStencilView_, clearFlag, depthVal, stencilVal); + context_->ClearDepthStencilView(curDepthStencilView_, clearFlag, depthVal, stencilVal); } } @@ -1130,6 +1136,8 @@ bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo) { D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; context_->OMSetRenderTargets(1, &fb->colorRTView, fb->depthStencilRTView); + curRenderTargetView_ = fb->colorRTView; + curDepthStencilView_ = fb->depthStencilRTView; } // color must be 0, for now. @@ -1144,6 +1152,8 @@ void D3D11DrawContext::BindFramebufferForRead(Framebuffer *fbo) { void D3D11DrawContext::BindBackbufferAsRenderTarget() { context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_); + curRenderTargetView_ = bbRenderTargetView_; + curDepthStencilView_ = bbDepthStencilView_; } uintptr_t D3D11DrawContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) { From a8dc9360f05c41d850b6ac890398ff1904111cbc Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 10 Feb 2017 10:32:32 +0100 Subject: [PATCH 13/40] D3D11: Fix clears --- GPU/D3D11/DrawEngineD3D11.cpp | 17 ++++++++--------- ext/native/thin3d/thin3d_d3d11.cpp | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index d7a79ad5e1..5e24b15156 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -895,30 +895,29 @@ rotateVBO: u32 clearColor = result.color; float clearDepth = result.depth; - UINT depthClearFlag = 0; + uint32_t clearFlag = 0; - /* - bool clearColor = gstate.isClearModeColorMask(); - if (gstate.isClearModeAlphaMask()) depthClearFlag |= D3D11_CLEAR_STENCIL; - if (gstate.isClearModeDepthMask()) depthClearFlag |= D3D11_CLEAR_DEPTH; + if (gstate.isClearModeColorMask()) clearFlag |= Draw::COLOR; + if (gstate.isClearModeAlphaMask()) clearFlag |= Draw::STENCIL; + if (gstate.isClearModeDepthMask()) clearFlag |= Draw::DEPTH; if (clearColor) { framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); } - if (depthClearFlag & D3D11_CLEAR_DEPTH) { + if (clearFlag & Draw::DEPTH) { framebufferManager_->SetDepthUpdated(); } int colorMask = 0; if (clearColor) colorMask |= 7; - if (depthClearFlag & D3D11_CLEAR_STENCIL) { + if (clearFlag & Draw::STENCIL) { colorMask |= 8; } context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[colorMask], nullptr, 0xFFFFFFFF); - device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24); - */ + uint8_t clearStencil = clearColor >> 24; + draw_->Clear(clearFlag, clearColor, clearDepth, clearStencil); int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index bffe80e27f..67c36080c2 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -1104,7 +1104,7 @@ void D3D11DrawContext::BindSamplerStates(int start, int count, SamplerState **st void D3D11DrawContext::Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) { if (mask & ClearFlag::COLOR) { float colorRGBA[4]; - Uint8x1ToFloat4(colorRGBA, colorval); + Uint8x4ToFloat4(colorRGBA, colorval); context_->ClearRenderTargetView(curRenderTargetView_, colorRGBA); } if (mask & (ClearFlag::DEPTH | ClearFlag::STENCIL)) { From 3f4e14f50423603f39f70036a5dbe6fdcbc0bdd7 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 10 Feb 2017 11:25:24 +0100 Subject: [PATCH 14/40] D3D11: Lumines is now playable in non-buffered, with reverse colors. --- GPU/Common/ShaderUniforms.cpp | 22 ++++++++++--- GPU/Common/ShaderUniforms.h | 38 ++++++++++++++++------ GPU/D3D11/D3D11Util.h | 3 +- GPU/D3D11/DrawEngineD3D11.cpp | 13 ++++---- GPU/D3D11/FramebufferManagerD3D11.cpp | 3 +- GPU/D3D11/GPU_D3D11.cpp | 1 + GPU/D3D11/ShaderManagerD3D11.cpp | 2 +- GPU/D3D11/TextureCacheD3D11.cpp | 12 ++++--- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 6 ++-- GPU/Vulkan/ShaderManagerVulkan.cpp | 2 +- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 2 +- Windows/GPU/D3D11Context.cpp | 16 ++++++--- Windows/GPU/D3D11Context.h | 1 + 13 files changed, 83 insertions(+), 38 deletions(-) diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 4fc4fff050..e5acc7bc27 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -7,13 +7,19 @@ #include "GPU/Math3D.h" #include "Core/Reporting.h" -static void ConvertProjMatrixToVulkan(Matrix4x4 &in, bool invertedX, bool invertedY) { +static void ConvertProjMatrixToVulkan(Matrix4x4 &in) { const Vec3 trans(0, 0, gstate_c.vpZOffset * 0.5f + 0.5f); const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); in.translateAndScale(trans, scale); } -void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms) { +static void ConvertProjMatrixToD3D11(Matrix4x4 &in) { + const Vec3 trans(0, 0, gstate_c.vpZOffset * 0.5f + 0.5f); + const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); + in.translateAndScale(trans, scale); +} + +void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport) { if (dirtyUniforms & DIRTY_TEXENV) { Uint8x3ToFloat4(ub->texEnvColor, gstate.texenvcolor); } @@ -65,13 +71,21 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms) { flippedMatrix[8] = -flippedMatrix[8]; flippedMatrix[12] = -flippedMatrix[12]; } - ConvertProjMatrixToVulkan(flippedMatrix, invertedX, invertedY); + if (flipViewport) { + ConvertProjMatrixToD3D11(flippedMatrix); + } else { + ConvertProjMatrixToVulkan(flippedMatrix); + } CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr()); } if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { Matrix4x4 proj_through; - proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1); + if (flipViewport) { + proj_through.setOrthoD3D(0.0f, gstate_c.curRTWidth, gstate_c.curRTHeight, 0, 0, 1); + } else { + proj_through.setOrthoVulkan(0.0f, gstate_c.curRTWidth, 0, gstate_c.curRTHeight, 0, 1); + } CopyMatrix4x4(ub->proj_through, proj_through.getReadPtr()); } diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index afceaee4ca..17ec2955bb 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -69,7 +69,7 @@ R"( float4x4 u_proj; float4x4 u_tex; float4 u_uvscaleoffset; float4 u_depthRange; - float3 u_fogcoef_stencilreplace; + float3 u_fogcoef; float4 u_matambientalpha; float3 u_fogcolor; float3 u_texenv; @@ -98,7 +98,7 @@ struct UB_VS_Lights { }; static const char *ub_vs_lightsStr = -R"( vec4 globalAmbient; +R"( vec4 u_ambient; vec3 matdiffuse; vec4 matspecular; vec3 matemissive; @@ -114,18 +114,36 @@ R"( vec4 globalAmbient; // HLSL code is shared so these names are changed to match those in DX9. static const char *cb_vs_lightsStr = -R"( float4 globalAmbient; +R"( float4 u_ambient; float3 u_matdiffuse; float4 u_matspecular; float3 u_matemissive; - float3 u_lightpos[4]; - float3 u_lightdir[4]; - float3 u_lightatt[4]; + float3 u_lightpos0; + float3 u_lightpos1; + float3 u_lightpos2; + float3 u_lightpos3; + float3 u_lightdir0; + float3 u_lightdir1; + float3 u_lightdir2; + float3 u_lightdir3; + float3 u_lightatt0; + float3 u_lightatt1; + float3 u_lightatt2; + float3 u_lightatt3; float u_lightangle[4]; float u_lightspotCoef[4]; - float3 u_ambient[4]; - float3 u_diffuse[4]; - float3 u_specular[4]; + float3 u_lightambient0; + float3 u_lightambient1; + float3 u_lightambient2; + float3 u_lightambient3; + float3 u_lightdiffuse0; + float3 u_lightdiffuse1; + float3 u_lightdiffuse2; + float3 u_lightdiffuse3; + float3 u_lightspecular0; + float3 u_lightspecular1; + float3 u_lightspecular2; + float3 u_lightspecular3; )"; // With some cleverness, we could get away with uploading just half this when only the four first @@ -144,7 +162,7 @@ static const char *cb_vs_bonesStr = R"( float4x4 m[8]; )"; -void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms); +void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipViewport); void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms); void BoneUpdateUniforms(UB_VS_Bones *ub, uint64_t dirtyUniforms); diff --git a/GPU/D3D11/D3D11Util.h b/GPU/D3D11/D3D11Util.h index 83296a13e6..cbac7a972a 100644 --- a/GPU/D3D11/D3D11Util.h +++ b/GPU/D3D11/D3D11Util.h @@ -44,8 +44,9 @@ public: nextMapDiscard_ = true; } - uint8_t *BeginPush(ID3D11DeviceContext *context, UINT *offset, size_t size) { + uint8_t *BeginPush(ID3D11DeviceContext *context, UINT *offset, size_t size, int align = 16) { D3D11_MAPPED_SUBRESOURCE map; + pos_ = (pos_ + align - 1) & ~(align - 1); context->Map(buffer_, 0, nextMapDiscard_ ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map); nextMapDiscard_ = false; *offset = (UINT)pos_; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 5e24b15156..a03cdc6139 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -587,6 +587,8 @@ void DrawEngineD3D11::DoFlush() { if (useHWTransform) { ID3D11Buffer *vb_ = nullptr; ID3D11Buffer *ib_ = nullptr; + if (prim == GE_PRIM_TRIANGLE_FAN) + Crash(); int vertexCount = 0; int maxIndex = 0; @@ -785,15 +787,13 @@ rotateVBO: context_->IASetVertexBuffers(0, 1, &buf, &stride, &vOffset); if (useElements) { UINT iOffset; - int iSize = 2 * vertexCount; + int iSize = 2 * indexGen.VertexCount(); uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize); memcpy(iptr, decIndex, iSize); pushInds_->EndPush(context_); context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset); context_->DrawIndexed(vertexCount, 0, 0); - // context_->DrawIndexedPrimitiveUP(glprim[prim], 0, maxIndex + 1, D3DPrimCount(glprim[prim], vertexCount), decIndex, D3DFMT_INDEX16, decoded, dec_->GetDecVtxFmt().stride); } else { - // context_->DrawPrimitiveUP(glprim[prim], D3DPrimCount(glprim[prim], vertexCount), decoded, dec_->GetDecVtxFmt().stride); context_->Draw(vertexCount, 0); } } else { @@ -873,7 +873,7 @@ rotateVBO: UINT stride = sizeof(TransformedVertex); UINT vOffset = 0; - int vSize = numTrans * dec_->GetDecVtxFmt().stride; + int vSize = maxIndex * stride; uint8_t *vptr = pushVerts_->BeginPush(context_, &vOffset, vSize); memcpy(vptr, drawBuffer, vSize); pushVerts_->EndPush(context_); @@ -881,13 +881,12 @@ rotateVBO: context_->IASetVertexBuffers(0, 1, &buf, &stride, &vOffset); if (drawIndexed) { UINT iOffset; - int iSize = 2 * (maxIndex + 1); + int iSize = sizeof(int16_t) * numTrans; uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize); memcpy(iptr, inds, iSize); pushInds_->EndPush(context_); context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset); - context_->DrawIndexed(maxIndex + 1, 0, 0); - // context_->DrawIndexedPrimitiveUP(glprim[prim], 0, maxIndex, numTrans, inds, DXGI_FORMAT_R16_UINT, drawBuffer, sizeof(TransformedVertex)); + context_->DrawIndexed(numTrans, 0, 0); } else { context_->Draw(numTrans, 0); } diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index c52a22ea7a..d0377ff320 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -453,7 +453,8 @@ void FramebufferManagerD3D11::BindFramebufferColor(int stage, VirtualFramebuffer } if (!framebuffer->fbo || !useBufferedRendering_) { - context_->PSSetShaderResources(stage, 1, nullptr); + ID3D11ShaderResourceView *view = nullptr; + context_->PSSetShaderResources(stage, 1, &view); gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; return; } diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index db05a454c8..73700325e7 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -557,6 +557,7 @@ void GPU_D3D11::DumpNextFrame() { void GPU_D3D11::BeginFrame() { ScheduleEvent(GPU_EVENT_BEGIN_FRAME); + gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX); } void GPU_D3D11::ReapplyGfxStateInternal() { diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index fe631c97c8..66067539aa 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -148,7 +148,7 @@ uint64_t ShaderManagerD3D11::UpdateUniforms() { if (dirty != 0) { D3D11_MAPPED_SUBRESOURCE map; if (dirty & DIRTY_BASE_UNIFORMS) { - BaseUpdateUniforms(&ub_base, dirty); + BaseUpdateUniforms(&ub_base, dirty, true); context_->Map(push_base, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); memcpy(map.pData, &ub_base, sizeof(ub_base)); context_->Unmap(push_base, 0); diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 946bfe3ad5..7603aa27fc 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -132,7 +132,8 @@ void TextureCacheD3D11::SetFramebufferManager(FramebufferManagerD3D11 *fbManager } void TextureCacheD3D11::Clear(bool delete_them) { - // context_->PSSetShaderResources(0, 1, nullptr); + // ID3D11ShaderResourceView *srv = nullptr; + // context_->PSSetShaderResources(0, 1, &srv); lastBoundTexture = INVALID_TEX; if (delete_them) { for (TexCache::iterator iter = cache.begin(); iter != cache.end(); ++iter) { @@ -182,7 +183,8 @@ void TextureCacheD3D11::Decimate() { if (cacheSizeEstimate_ >= TEXCACHE_MIN_PRESSURE) { const u32 had = cacheSizeEstimate_; - context_->PSSetShaderResources(0, 1, nullptr); + ID3D11ShaderResourceView *srv = nullptr; + context_->PSSetShaderResources(0, 1, &srv); lastBoundTexture = INVALID_TEX; int killAge = lowMemoryMode_ ? TEXTURE_KILL_AGE_LOWMEM : TEXTURE_KILL_AGE; for (TexCache::iterator iter = cache.begin(); iter != cache.end(); ) { @@ -603,7 +605,8 @@ void TextureCacheD3D11::SetTexture(bool force) { u32 texaddr = gstate.getTextureAddress(0); if (!Memory::IsValidAddress(texaddr)) { // Bind a null texture and return. - context_->PSSetShaderResources(0, 1, nullptr); + ID3D11ShaderResourceView *srv = nullptr; + context_->PSSetShaderResources(0, 1, &srv); lastBoundTexture = INVALID_TEX; return; } @@ -1000,7 +1003,8 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry, bool replaceIma if (replaceImages) { // Make sure it's not currently set. - context_->PSSetShaderResources(0, 1, nullptr); + ID3D11ShaderResourceView *srv = nullptr; + context_->PSSetShaderResources(0, 1, &srv); } // Seems to cause problems in Tactics Ogre. diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index 15cd493a68..c5f8b734e5 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -254,7 +254,7 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l } WRITE(p, "VS_OUT main(VS_IN In) {\n"); - WRITE(p, " VS_OUT Out = (VS_OUT)0; \n"); + WRITE(p, " VS_OUT Out;\n"); if (!useHWTransform) { // Simple pass-through of vertex data to fragment shader if (doTexture) { @@ -304,13 +304,13 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l if (lang == HLSL_D3D11) { WRITE(p, " float3 worldpos = mul(u_world, float4(In.position.xyz, 1.0)).xyz;\n"); if (hasNormal) - WRITE(p, " float3 worldnormal = normalize( mul(u_world, float4(%sIn.normal, 0.0)));\n", flipNormal ? "-" : ""); + WRITE(p, " float3 worldnormal = normalize(mul(u_world, float4(%sIn.normal, 0.0))).xyz;\n", flipNormal ? "-" : ""); else WRITE(p, " float3 worldnormal = float3(0.0, 0.0, 1.0);\n"); } else { WRITE(p, " float3 worldpos = mul(float4(In.position.xyz, 1.0), u_world);\n"); if (hasNormal) - WRITE(p, " float3 worldnormal = normalize( mul(float4(%sIn.normal, 0.0), u_world));\n", flipNormal ? "-" : ""); + WRITE(p, " float3 worldnormal = normalize(mul(float4(%sIn.normal, 0.0), u_world));\n", flipNormal ? "-" : ""); else WRITE(p, " float3 worldnormal = float3(0.0, 0.0, 1.0);\n"); } diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index b36f47d4c2..ec2d62baf3 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -222,7 +222,7 @@ uint64_t ShaderManagerVulkan::UpdateUniforms() { uint64_t dirty = gstate_c.GetDirtyUniforms(); if (dirty != 0) { if (dirty & DIRTY_BASE_UNIFORMS) - BaseUpdateUniforms(&ub_base, dirty); + BaseUpdateUniforms(&ub_base, dirty, false); if (dirty & DIRTY_LIGHT_UNIFORMS) LightUpdateUniforms(&ub_lights, dirty); if (dirty & DIRTY_BONE_UNIFORMS) diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index d121ad6431..32a4326d87 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -304,7 +304,7 @@ bool GenerateVulkanGLSLVertexShader(const ShaderID &id, char *buffer, bool *uses bool distanceNeeded = false; if (enableLighting) { - WRITE(p, " vec4 lightSum0 = light.globalAmbient * %s + vec4(light.matemissive, 0.0);\n", ambientStr); + WRITE(p, " vec4 lightSum0 = light.u_ambient * %s + vec4(light.matemissive, 0.0);\n", ambientStr); for (int i = 0; i < 4; i++) { GELightType type = static_cast(id.Bits(VS_BIT_LIGHT0_TYPE + 4 * i, 2)); diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index 37e497010f..13a189a7f5 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -75,11 +75,10 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { #ifdef _DEBUG if (SUCCEEDED(device_->QueryInterface(__uuidof(ID3D11Debug), (void**)&d3dDebug_))) { - ID3D11InfoQueue *d3dInfoQueue = nullptr; - if (SUCCEEDED(d3dDebug_->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&d3dInfoQueue))) { - d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); - d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); - d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true); + if (SUCCEEDED(d3dDebug_->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&d3dInfoQueue_))) { + d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); + d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); + d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true); } } #endif @@ -112,9 +111,16 @@ void D3D11Context::Resize() { } void D3D11Context::Shutdown() { +#ifdef _DEBUG + d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, false); + d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, false); + d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, false); +#endif #ifdef _DEBUG d3dDebug_->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL); #endif + d3dDebug_->Release(); + d3dInfoQueue_->Release(); context_->ClearState(); context_->Flush(); diff --git a/Windows/GPU/D3D11Context.h b/Windows/GPU/D3D11Context.h index 927394c3c6..2b71ffbc63 100644 --- a/Windows/GPU/D3D11Context.h +++ b/Windows/GPU/D3D11Context.h @@ -45,6 +45,7 @@ private: #ifdef _DEBUG ID3D11Debug *d3dDebug_ = nullptr; + ID3D11InfoQueue *d3dInfoQueue_ = nullptr; #endif D3D_DRIVER_TYPE driverType_; From 7750ee9f7b9b9717efe5cc887496a27109a50594 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Fri, 10 Feb 2017 11:36:09 +0100 Subject: [PATCH 15/40] D3D11: Fix reversed colors, stencil improvements --- GPU/D3D11/StateMappingD3D11.cpp | 27 ++++++++++++++--------- GPU/D3D11/TextureCacheD3D11.cpp | 2 +- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 6 ++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index d88285d181..02f9329dcf 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -156,10 +156,12 @@ struct D3D11DepthStencilKey { 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 stencilCompareOp : 4; // D3D11_COMPARISON + 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 { @@ -179,8 +181,6 @@ struct D3D11DynamicState { uint32_t blendColor; bool useStencil; uint8_t stencilRef; - uint8_t stencilWriteMask; - uint8_t stencilCompareMask; D3D11_VIEWPORT viewport; D3D11_RECT scissor; }; @@ -259,7 +259,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { // Stencil Test if (alphaMask) { key.depthStencil.stencilTestEnable = true; - key.depthStencil.stencilCompareOp = D3D11_COMPARISON_ALWAYS; + 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; @@ -268,7 +268,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { // 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; - dynState.stencilWriteMask = 0xFF; + key.depthStencil.stencilWriteMask = 0xFF; } else { key.depthStencil.stencilTestEnable = false; dynState.useStencil = false; @@ -341,14 +341,14 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { // Stencil Test if (stencilState.enabled) { key.depthStencil.stencilTestEnable = true; - key.depthStencil.stencilCompareOp = compareOps[stencilState.testFunc]; + 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; - dynState.stencilCompareMask = stencilState.testMask; - dynState.stencilWriteMask = stencilState.writeMask; } else { key.depthStencil.stencilTestEnable = false; dynState.useStencil = false; @@ -426,9 +426,14 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { 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 = FALSE; // keys.depthStencil.stencilTestEnable; - - // ... + 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.BackFace = desc.FrontFace; device_->CreateDepthStencilState(&desc, &ds); depthStencilCache_.insert(std::pair(depthKey, ds)); } else { diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 7603aa27fc..97318afb4c 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -644,7 +644,7 @@ void TextureCacheD3D11::SetTexture(bool force) { TexCache::iterator iter = cache.find(cachekey); TexCacheEntry *entry = NULL; gstate_c.needShaderTexClamp = false; - gstate_c.bgraTexture = true; + gstate_c.bgraTexture = false; gstate_c.skipDrawReason &= ~SKIPDRAW_BAD_FB_TEXTURE; bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index c5f8b734e5..b9ff0f0dd1 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -124,7 +124,7 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l WRITE(p, "float4x3 u_world : register(c%i);\n", CONST_VS_WORLD); WRITE(p, "float4x3 u_view : register(c%i);\n", CONST_VS_VIEW); if (doTextureTransform) - WRITE(p, "float4x3 u_texmtx : register(c%i);\n", CONST_VS_TEXMTX); + WRITE(p, "float4x3 u_tex : register(c%i);\n", CONST_VS_TEXMTX); if (enableBones) { #ifdef USE_BONE_ARRAY WRITE(p, "float4x3 u_bone[%i] : register(c%i);\n", numBones, CONST_VS_BONE0); @@ -586,9 +586,9 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l } // Transform by texture matrix. XYZ as we are doing projection mapping. if (lang == HLSL_D3D11) { - WRITE(p, " Out.v_texcoord.xyz = (mul(%s, u_texmtx) * float4(u_uvscaleoffset.xy, 1.0, 0.0)).xyz;\n", temp_tc.c_str()); + WRITE(p, " Out.v_texcoord.xyz = (mul(u_tex, %s) * float4(u_uvscaleoffset.xy, 1.0, 0.0)).xyz;\n", temp_tc.c_str()); } else { - WRITE(p, " Out.v_texcoord.xyz = mul(%s, u_texmtx) * float3(u_uvscaleoffset.xy, 1.0);\n", temp_tc.c_str()); + WRITE(p, " Out.v_texcoord.xyz = mul(%s, u_tex) * float3(u_uvscaleoffset.xy, 1.0);\n", temp_tc.c_str()); } } break; From f7717063a8fee7df5b935a6b6a48445670fd090c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 10 Feb 2017 14:41:32 +0100 Subject: [PATCH 16/40] Assorted fixes for memory leaks etc --- GPU/D3D11/FramebufferManagerD3D11.cpp | 6 ++++++ GPU/D3D11/FramebufferManagerD3D11.h | 2 +- GPU/D3D11/GPU_D3D11.cpp | 4 +++- GPU/D3D11/TextureCacheD3D11.cpp | 3 ++- GPU/Directx9/GPU_DX9.cpp | 2 ++ GPU/GLES/GPU_GLES.cpp | 3 ++- GPU/GPUCommon.cpp | 1 - Windows/GPU/D3D11Context.cpp | 22 +++++----------------- 8 files changed, 21 insertions(+), 22 deletions(-) diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index d0377ff320..d48bde41e1 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -120,6 +120,9 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) FramebufferManagerD3D11::~FramebufferManagerD3D11() { // Drawing cleanup + if (vbFullScreenRect_) { + vbFullScreenRect_->Release(); + } if (pFramebufferVertexShader_) { pFramebufferVertexShader_->Release(); pFramebufferVertexShader_ = nullptr; @@ -132,6 +135,9 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() { if (drawPixelsTex_) { drawPixelsTex_->Release(); } + if (drawPixelsTexView_) { + drawPixelsTexView_->Release(); + } // FBO cleanup for (auto it = tempFBOs_.begin(), end = tempFBOs_.end(); it != end; ++it) { diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index a9cf0b91df..5527d54297 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -127,7 +127,7 @@ private: ShaderManagerD3D11 *shaderManager_; DrawEngineD3D11 *drawEngine_; - ID3D11Buffer *vbFullScreenRect_; + ID3D11Buffer *vbFullScreenRect_ = nullptr; UINT vbFullScreenStride_ = 20; UINT vbFullScreenOffset_ = 0; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 73700325e7..978a292550 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -479,9 +479,11 @@ GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw) GPU_D3D11::~GPU_D3D11() { delete depalShaderCache_; framebufferManagerD3D11_->DestroyAllFBOs(true); + delete framebufferManagerD3D11_; shaderManagerD3D11_->ClearShaders(); - draw_->BindPipeline(nullptr); delete shaderManagerD3D11_; + delete textureCacheD3D11_; + draw_->BindPipeline(nullptr); stockD3D11.Destroy(); } diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 97318afb4c..1b1239df1a 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -1110,8 +1110,9 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & tfmt = DXGI_FORMAT_R8G8B8A8_UNORM; } } + D3D11_TEXTURE2D_DESC desc{}; - // TODO: Make it immutable, will requires some code restructuring though. + // TODO: Make it DEFAULT or immutable, required for multiple mip levels. Will require some code restructuring though. desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; desc.Usage = D3D11_USAGE_DYNAMIC; desc.ArraySize = 1; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 4118111908..3f87dc2e0f 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -513,6 +513,8 @@ void GPU_DX9::CheckGPUFeatures() { GPU_DX9::~GPU_DX9() { framebufferManagerDX9_->DestroyAllFBOs(true); + delete framebufferManagerDX9_; + delete textureCache_; shaderManagerDX9_->ClearCache(true); delete shaderManagerDX9_; } diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 05745727a6..60ff75517d 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -495,7 +495,8 @@ GPU_GLES::~GPU_GLES() { } delete shaderManagerGL_; shaderManagerGL_ = nullptr; - + delete framebufferManagerGL_; + delete textureCacheGL_; #ifdef _WIN32 gfxCtx_->SwapInterval(0); #endif diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 1058f109b3..e9a0836ba6 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -54,7 +54,6 @@ GPUCommon::GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : } GPUCommon::~GPUCommon() { - delete framebufferManager_; } void GPUCommon::BeginHostFrame() { diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index 13a189a7f5..eb12c1f65c 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -111,6 +111,11 @@ void D3D11Context::Resize() { } void D3D11Context::Shutdown() { + delete draw_; + draw_ = nullptr; + context_->ClearState(); + context_->Flush(); + #ifdef _DEBUG d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, false); d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, false); @@ -121,27 +126,10 @@ void D3D11Context::Shutdown() { #endif d3dDebug_->Release(); d3dInfoQueue_->Release(); - context_->ClearState(); - context_->Flush(); - - delete draw_; - draw_ = nullptr; context_->Release(); context_ = nullptr; device_->Release(); device_ = nullptr; - /* - DX9::DestroyShaders(); - device->EndScene(); - device->Release(); - d3d->Release(); - UnloadD3DXDynamic(); - DX9::pD3Ddevice = nullptr; - DX9::pD3DdeviceEx = nullptr; - DX9::pD3D = nullptr; - */ hWnd_ = nullptr; - // FreeLibrary(hD3D11); - // hD3D11 = nullptr; } From 04b803e2f686d2262278942648744e1954cdf5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 10 Feb 2017 15:40:51 +0100 Subject: [PATCH 17/40] D3D11: Change init method for textures, so we can support mipmapping --- GPU/D3D11/TextureCacheD3D11.cpp | 33 ++++++++++++++++++--------------- ext/native/thin3d/thin3d.h | 1 + 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 1b1239df1a..c418e31786 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -1113,8 +1113,8 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & D3D11_TEXTURE2D_DESC desc{}; // TODO: Make it DEFAULT or immutable, required for multiple mip levels. Will require some code restructuring though. - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.Usage = D3D11_USAGE_DYNAMIC; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; desc.ArraySize = 1; desc.SampleDesc.Count = 1; desc.Width = tw; @@ -1131,17 +1131,17 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & } ID3D11ShaderResourceView *view; hr = device_->CreateShaderResourceView(texture, nullptr, &view); - entry.texturePtr = texture; entry.textureView = view; } - D3D11_MAPPED_SUBRESOURCE map; - context_->Map(texture, level, D3D11_MAP_WRITE_DISCARD, 0, &map); - gpuStats.numTexturesDecoded++; + // For UpdateSubresource, we can't decode directly into the texture so we allocate a buffer :( + u32 *mapData = new u32[w * h]{}; + int mapRowPitch = w * 4; + if (replaced.GetSize(level, w, h)) { - replaced.Load(level, map.pData, map.RowPitch); + replaced.Load(level, mapData, mapRowPitch); dstFmt = ToDXGIFormat(replaced.Format(level)); } else { GETextureFormat tfmt = (GETextureFormat)entry.format; @@ -1150,8 +1150,8 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & int bufw = GetTextureBufw(level, texaddr, tfmt); int bpp = dstFmt == DXGI_FORMAT_R8G8B8A8_UNORM ? 4 : 2; - u32 *pixelData = (u32 *)map.pData; - int decPitch = map.RowPitch; + u32 *pixelData = (u32 *)mapData; + int decPitch = mapRowPitch; if (scaleFactor > 1) { tmpTexBufRearrange.resize(std::max(bufw, w) * h); pixelData = tmpTexBufRearrange.data(); @@ -1165,21 +1165,22 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & } if (scaleFactor > 1) { - scaler.ScaleAlways((u32 *)map.pData, pixelData, dstFmt, w, h, scaleFactor); - pixelData = (u32 *)map.pData; + scaler.ScaleAlways((u32 *)mapData, pixelData, dstFmt, w, h, scaleFactor); + pixelData = (u32 *)mapData; // We always end up at 8888. Other parts assume this. assert(dstFmt == DXGI_FORMAT_R8G8B8A8_UNORM); bpp = sizeof(u32); decPitch = w * bpp; - if (decPitch != map.RowPitch) { + if (decPitch != mapRowPitch) { // Rearrange in place to match the requested pitch. // (it can only be larger than w * bpp, and a match is likely.) + // Note! This is bad because it reads the mapped memory! TODO: Look into if DX9 does this right. for (int y = h - 1; y >= 0; --y) { - memcpy((u8 *)map.pData + map.RowPitch * y, (u8 *)map.pData + decPitch * y, w * bpp); + memcpy((u8 *)mapData + mapRowPitch * y, (u8 *)mapData + decPitch * y, w * bpp); } - decPitch = map.RowPitch; + decPitch = mapRowPitch; } } @@ -1203,7 +1204,9 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & replacer.NotifyTextureDecoded(replacedInfo, pixelData, decPitch, level, w, h); } } - context_->Unmap(texture, level); + + context_->UpdateSubresource(texture, level, nullptr, mapData, mapRowPitch, 0); + delete[] mapData; } bool TextureCacheD3D11::DecodeTexture(u8 *output, const GPUgstate &state) { diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index f58c618704..2f3eec4aac 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -459,6 +459,7 @@ public: class Pipeline : public RefCountedObject { public: + virtual ~Pipeline() {} virtual bool RequiresBuffer() = 0; }; From 0ae06b014848108de2c905b8fa4790391d0b9007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 11 Feb 2017 10:52:43 +0100 Subject: [PATCH 18/40] Android buildfix --- android/jni/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 24c0b6dc1e..9a73162e85 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -224,6 +224,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/Common/TransformCommon.cpp.arm \ $(SRC)/GPU/Common/TextureDecoder.cpp \ $(SRC)/GPU/Common/PostShader.cpp \ + $(SRC)/GPU/Common/ShaderUniforms.cpp \ $(SRC)/GPU/Debugger/Breakpoints.cpp \ $(SRC)/GPU/Debugger/Stepping.cpp \ $(SRC)/GPU/GLES/FramebufferManagerGLES.cpp \ From abbd6cb1d106a052fe4ccd0ca6eb26fc35c04f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 11:20:55 +0100 Subject: [PATCH 19/40] Fix DrawActiveTexture, now Buffered Rendering is starting to work --- GPU/D3D11/D3D11Util.cpp | 10 ++ GPU/D3D11/D3D11Util.h | 2 + GPU/D3D11/FramebufferManagerD3D11.cpp | 128 ++++++++++++++------------ GPU/D3D11/FramebufferManagerD3D11.h | 9 +- GPU/D3D11/GPU_D3D11.cpp | 2 + GPU/D3D11/StateMappingD3D11.cpp | 47 +++++----- GPU/D3D11/TextureCacheD3D11.cpp | 2 +- GPU/GLES/FramebufferManagerGLES.cpp | 2 +- ext/native/thin3d/thin3d.h | 2 +- ext/native/thin3d/thin3d_d3d11.cpp | 31 ++++++- ext/native/thin3d/thin3d_d3d9.cpp | 2 +- ext/native/thin3d/thin3d_gl.cpp | 28 ++++-- ext/native/thin3d/thin3d_vulkan.cpp | 33 +++++-- 13 files changed, 190 insertions(+), 108 deletions(-) diff --git a/GPU/D3D11/D3D11Util.cpp b/GPU/D3D11/D3D11Util.cpp index 10766491c9..baff704f05 100644 --- a/GPU/D3D11/D3D11Util.cpp +++ b/GPU/D3D11/D3D11Util.cpp @@ -57,6 +57,7 @@ void StockObjectsD3D11::Create(ID3D11Device *device) { blend_desc.RenderTarget[0].RenderTargetWriteMask = i; device->CreateBlendState(&blend_desc, &blendStateDisabledWithColorMask[i]); } + D3D11_DEPTH_STENCIL_DESC depth_desc{}; depth_desc.DepthEnable = FALSE; device->CreateDepthStencilState(&depth_desc, &depthStencilDisabled); @@ -72,11 +73,13 @@ void StockObjectsD3D11::Create(ID3D11Device *device) { depth_desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; depth_desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; device->CreateDepthStencilState(&depth_desc, &depthDisabledStencilWrite); + D3D11_RASTERIZER_DESC raster_desc{}; raster_desc.FillMode = D3D11_FILL_SOLID; raster_desc.CullMode = D3D11_CULL_NONE; raster_desc.ScissorEnable = FALSE; device->CreateRasterizerState(&raster_desc, &rasterStateNoCull); + D3D11_SAMPLER_DESC sampler_desc{}; sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; @@ -85,6 +88,13 @@ void StockObjectsD3D11::Create(ID3D11Device *device) { device->CreateSamplerState(&sampler_desc, &samplerPoint2DWrap); sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; device->CreateSamplerState(&sampler_desc, &samplerLinear2DWrap); + sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + device->CreateSamplerState(&sampler_desc, &samplerPoint2DClamp); + sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + device->CreateSamplerState(&sampler_desc, &samplerLinear2DClamp); } void StockObjectsD3D11::Destroy() { diff --git a/GPU/D3D11/D3D11Util.h b/GPU/D3D11/D3D11Util.h index cbac7a972a..4718756731 100644 --- a/GPU/D3D11/D3D11Util.h +++ b/GPU/D3D11/D3D11Util.h @@ -78,6 +78,8 @@ public: ID3D11RasterizerState *rasterStateNoCull; ID3D11SamplerState *samplerPoint2DWrap; ID3D11SamplerState *samplerLinear2DWrap; + ID3D11SamplerState *samplerPoint2DClamp; + ID3D11SamplerState *samplerLinear2DClamp; }; extern StockObjectsD3D11 stockD3D11; \ No newline at end of file diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index d48bde41e1..4b47dfa89e 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -17,6 +17,7 @@ #include "math/lin/matrix4x4.h" #include "ext/native/thin3d/thin3d.h" +#include "base/basictypes.h" #include "Common/ColorConv.h" #include "Core/Host.h" @@ -43,7 +44,7 @@ #include #endif -static const char * vscode = +static const char *vscode = "struct VS_IN {\n" " float4 ObjPos : POSITION;\n" " float2 Uv : TEXCOORD0;\n" @@ -59,10 +60,7 @@ static const char * vscode = " return Out;\n" "}\n"; -//-------------------------------------------------------------------------------------- -// Pixel shader -//-------------------------------------------------------------------------------------- -static const char * pscode = +static const char *pscode = "SamplerState samp : register(s0);\n" "Texture2D tex : register(t0);\n" "struct PS_IN {\n" @@ -73,21 +71,11 @@ static const char * pscode = " return c;\n" "}\n"; -static const D3D11_INPUT_ELEMENT_DESC g_FramebufferVertexElements[] = { +static const D3D11_INPUT_ELEMENT_DESC g_QuadVertexElements[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, }, }; -void FramebufferManagerD3D11::ClearBuffer(bool keepState) { - draw_->Clear(Draw::ClearFlag::COLOR | Draw::ClearFlag::DEPTH | Draw::ClearFlag::STENCIL, 0, ToScaledDepth(0), 0); -} - -void FramebufferManagerD3D11::DisableState() { - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF); - context_->RSSetState(stockD3D11.rasterStateNoCull); - context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0xFF); -} - FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) : FramebufferManagerCommon(draw), drawPixelsTex_(0), @@ -102,20 +90,27 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) std::vector bytecode; std::string errorMsg; - pFramebufferVertexShader_ = CreateVertexShaderD3D11(device_, vscode, strlen(vscode), &bytecode); - pFramebufferPixelShader_ = CreatePixelShaderD3D11(device_, pscode, strlen(pscode)); - device_->CreateInputLayout(g_FramebufferVertexElements, ARRAY_SIZE(g_FramebufferVertexElements), bytecode.data(), bytecode.size(), &pFramebufferVertexDecl_); + quadVertexShader_ = CreateVertexShaderD3D11(device_, vscode, strlen(vscode), &bytecode); + quadPixelShader_ = CreatePixelShaderD3D11(device_, pscode, strlen(pscode)); + device_->CreateInputLayout(g_QuadVertexElements, ARRAY_SIZE(g_QuadVertexElements), bytecode.data(), bytecode.size(), &quadVertexDecl_); - float coord[20] = { - -1.0f,-1.0f, 0, 0,0, - 1.0f,-1.0f, 0, 0,0, - 1.0f,1.0f, 0, 0,0, - -1.0f,1.0f, 0, 0,0, + // STRIP geometry + static const float fsCoord[20] = { + -1.0f,-1.0f, 0.0f, 0.0f, 0.0f, + 1.0f,-1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, }; D3D11_BUFFER_DESC vb{}; vb.ByteWidth = 20 * 4; vb.Usage = D3D11_USAGE_IMMUTABLE; vb.CPUAccessFlags = 0; + vb.BindFlags = D3D11_BIND_VERTEX_BUFFER; + D3D11_SUBRESOURCE_DATA data{ fsCoord }; + device_->CreateBuffer(&vb, &data, &fsQuadBuffer_); + vb.Usage = D3D11_USAGE_DYNAMIC; + vb.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + device_->CreateBuffer(&vb, nullptr, &quadBuffer_); } FramebufferManagerD3D11::~FramebufferManagerD3D11() { @@ -123,21 +118,23 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() { if (vbFullScreenRect_) { vbFullScreenRect_->Release(); } - if (pFramebufferVertexShader_) { - pFramebufferVertexShader_->Release(); - pFramebufferVertexShader_ = nullptr; + if (quadVertexShader_) { + quadVertexShader_->Release(); + quadVertexShader_ = nullptr; } - if (pFramebufferPixelShader_) { - pFramebufferPixelShader_->Release(); - pFramebufferPixelShader_ = nullptr; + if (quadPixelShader_) { + quadPixelShader_->Release(); + quadPixelShader_ = nullptr; } - pFramebufferVertexDecl_->Release(); + quadVertexDecl_->Release(); if (drawPixelsTex_) { drawPixelsTex_->Release(); } if (drawPixelsTexView_) { drawPixelsTexView_->Release(); } + quadBuffer_->Release(); + fsQuadBuffer_->Release(); // FBO cleanup for (auto it = tempFBOs_.begin(), end = tempFBOs_.end(); it != end; ++it) { @@ -163,6 +160,16 @@ void FramebufferManagerD3D11::SetTextureCache(TextureCacheD3D11 *tc) { textureCache_ = tc; } +void FramebufferManagerD3D11::ClearBuffer(bool keepState) { + draw_->Clear(Draw::ClearFlag::COLOR | Draw::ClearFlag::DEPTH | Draw::ClearFlag::STENCIL, 0, ToScaledDepth(0), 0); +} + +void FramebufferManagerD3D11::DisableState() { + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF); + context_->RSSetState(stockD3D11.rasterStateNoCull); + context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0xFF); +} + void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height) { u8 *convBuf = NULL; @@ -281,7 +288,6 @@ void FramebufferManagerD3D11::DrawFramebufferToOutput(const u8 *srcPixels, GEBuf } void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, bool linearFilter) { - // TODO: StretchRect instead? float coord[20] = { x,y,0, u0,v0, x + w,y,0, u1,v0, @@ -320,17 +326,30 @@ void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float coord[i * 5 + 1] = -(coord[i * 5 + 1] * invDestH - 1.0f - halfPixelY); } + // The above code is for FAN geometry but we can only do STRIP. So rearrange it a little. + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(quadBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + float *dest = (float *)map.pData; + memcpy(dest, coord, sizeof(float) * 5); + memcpy(dest + 5, coord + 5, sizeof(float) * 5); + memcpy(dest + 10, coord + 15, sizeof(float) * 5); + memcpy(dest + 15, coord + 10, sizeof(float) * 5); + context_->Unmap(quadBuffer_, 0); + context_->RSSetState(stockD3D11.rasterStateNoCull); context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF); - context_->IASetInputLayout(pFramebufferVertexDecl_); - context_->PSSetShader(pFramebufferPixelShader_, 0, 0); - context_->VSSetShader(pFramebufferVertexShader_, 0, 0); + context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0); + context_->IASetInputLayout(quadVertexDecl_); + context_->PSSetShader(quadPixelShader_, 0, 0); + context_->VSSetShader(quadVertexShader_, 0, 0); context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context_->PSSetSamplers(0, 1, linearFilter ? &stockD3D11.samplerLinear2DWrap : &stockD3D11.samplerPoint2DWrap); + context_->PSSetSamplers(0, 1, linearFilter ? &stockD3D11.samplerLinear2DClamp : &stockD3D11.samplerPoint2DClamp); + UINT stride = 20; + UINT offset = 0; + context_->IASetVertexBuffers(0, 1, &quadBuffer_, &stride, &offset); + context_->Draw(4, 0); - // TODO: DrawRectBuffer ? shaderManager_->DirtyLastShader(); - context_->Draw(2, 0); } void FramebufferManagerD3D11::RebindFramebuffer() { @@ -361,9 +380,9 @@ void FramebufferManagerD3D11::ReformatFramebufferFrom(VirtualFramebuffer *vfb, G context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0], nullptr, 0xFFFFFFFF); context_->RSSetState(stockD3D11.rasterStateNoCull); - context_->IASetInputLayout(pFramebufferVertexDecl_); - context_->PSSetShader(pFramebufferPixelShader_, nullptr, 0); - context_->VSSetShader(pFramebufferVertexShader_, nullptr, 0); + context_->IASetInputLayout(quadVertexDecl_); + context_->PSSetShader(quadPixelShader_, nullptr, 0); + context_->VSSetShader(quadVertexShader_, nullptr, 0); context_->IASetVertexBuffers(0, 1, &vbFullScreenRect_, &vbFullScreenStride_, &vbFullScreenOffset_); shaderManager_->DirtyLastShader(); D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }; @@ -404,13 +423,13 @@ void FramebufferManagerD3D11::BlitFramebufferDepth(VirtualFramebuffer *src, Virt if (g_Config.bDisableSlowFramebufEffects) { return; } - /* bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0; bool matchingSize = src->width == dst->width && src->height == dst->height; if (matchingDepthBuffer && matchingSize) { // 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); @@ -448,9 +467,9 @@ void FramebufferManagerD3D11::BlitFramebufferDepth(VirtualFramebuffer *src, Virt dstTex->UnlockRect(0); } } - RebindFramebuffer(); - }*/ + */ + } } void FramebufferManagerD3D11::BindFramebufferColor(int stage, VirtualFramebuffer *framebuffer, int flags) { @@ -527,10 +546,11 @@ void FramebufferManagerD3D11::CopyDisplayToOutput() { if (useBufferedRendering_) { // In buffered, we no longer clear the backbuffer before we start rendering. ClearBuffer(); - D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, 0.0f, 1.0f }; - context_->RSSetViewports(1, &vp); } + D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, 0.0f, 1.0f }; + context_->RSSetViewports(1, &vp); + u32 offsetX = 0; u32 offsetY = 0; @@ -630,19 +650,9 @@ void FramebufferManagerD3D11::CopyDisplayToOutput() { if (1) { const u32 rw = PSP_CoreParameter().pixelWidth; const u32 rh = PSP_CoreParameter().pixelHeight; - bool result = draw_->BlitFramebuffer(vfb->fbo, - (LONG)(u0 * vfb->renderWidth), (LONG)(v0 * vfb->renderHeight), (LONG)(u1 * vfb->renderWidth), (LONG)(v1 * vfb->renderHeight), - nullptr, - (LONG)(x * rw / w), (LONG)(y * rh / h), (LONG)((x + w) * rw / w), (LONG)((y + h) * rh / h), - Draw::FB_COLOR_BIT, - g_Config.iBufFilter == SCALE_LINEAR ? Draw::FB_BLIT_LINEAR : Draw::FB_BLIT_NEAREST); - if (!result) { - ERROR_LOG_REPORT_ONCE(blit_fail, G3D, "fbo_blit_color failed on display"); - D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, 0.0f, 1.0f }; - context_->RSSetViewports(1, &vp); - DrawActiveTexture(x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, u0, v0, u1, v1, uvRotation, g_Config.iBufFilter == SCALE_LINEAR); - } + DrawActiveTexture(x, y, w, h, (float)PSP_CoreParameter().pixelWidth, (float)PSP_CoreParameter().pixelHeight, u0, v0, u1, v1, uvRotation, g_Config.iBufFilter == SCALE_LINEAR); } + /* else if (usePostShader_ && extraFBOs_.size() == 1 && !postShaderAtOutputResolution_) { // An additional pass, post-processing shader to the extra FBO. diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 5527d54297..18c6ab359d 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -110,9 +110,12 @@ private: int drawPixelsTexW_; int drawPixelsTexH_; - ID3D11VertexShader *pFramebufferVertexShader_; - ID3D11PixelShader *pFramebufferPixelShader_; - ID3D11InputLayout *pFramebufferVertexDecl_; + ID3D11VertexShader *quadVertexShader_; + ID3D11PixelShader *quadPixelShader_; + ID3D11InputLayout *quadVertexDecl_; + // Dynamic + ID3D11Buffer *quadBuffer_; + ID3D11Buffer *fsQuadBuffer_; u8 *convBuf; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 978a292550..395e3eee80 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -509,6 +509,8 @@ void GPU_D3D11::CheckGPUFeatures() { features |= GPU_SUPPORTS_ANISOTROPY; features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; + // features |= GPU_SUPPORTS_ANY_COPY_IMAGE; + if (!g_Config.bHighQualityDepth) { features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 02f9329dcf..ece0497732 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -198,12 +198,6 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; - ViewportAndScissor vpAndScissor; - ConvertViewportAndScissor(useBufferedRendering, - framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(), - framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(), - vpAndScissor); - if (blendState.applyShaderBlending) { if (ApplyShaderBlending()) { // We may still want to do something about stencil -> alpha. @@ -357,22 +351,11 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { dynState.topology = primToD3D11[prim]; - D3D11_VIEWPORT &vp = dynState.viewport; - vp.TopLeftX = vpAndScissor.viewportX; - vp.TopLeftY = vpAndScissor.viewportY; - vp.Width = vpAndScissor.viewportW; - vp.Height = vpAndScissor.viewportH; - vp.MinDepth = vpAndScissor.depthRangeMin; - vp.MaxDepth = vpAndScissor.depthRangeMax; - if (vpAndScissor.dirtyProj) { - gstate_c.Dirty(DIRTY_PROJMATRIX); - } - - D3D11_RECT &scissor = dynState.scissor; - scissor.left = vpAndScissor.scissorX; - scissor.top = vpAndScissor.scissorY; - scissor.right = vpAndScissor.scissorX + vpAndScissor.scissorW; - scissor.bottom = vpAndScissor.scissorY + vpAndScissor.scissorH; + ViewportAndScissor vpAndScissor; + ConvertViewportAndScissor(useBufferedRendering, + framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(), + framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(), + vpAndScissor); float depthMin = vpAndScissor.depthRangeMin; float depthMax = vpAndScissor.depthRangeMax; @@ -383,6 +366,26 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { gstate_c.Dirty(DIRTY_DEPTHRANGE); } + D3D11_VIEWPORT &vp = dynState.viewport; + vp.TopLeftX = vpAndScissor.viewportX; + vp.TopLeftY = vpAndScissor.viewportY; + vp.Width = vpAndScissor.viewportW; + vp.Height = vpAndScissor.viewportH; + vp.MinDepth = depthMin; + vp.MaxDepth = depthMax; + if (vpAndScissor.dirtyProj) { + gstate_c.Dirty(DIRTY_PROJMATRIX); + } + context_->RSSetViewports(1, &vp); + + /* + D3D11_RECT &scissor = dynState.scissor; + scissor.left = vpAndScissor.scissorX; + scissor.top = vpAndScissor.scissorY; + scissor.right = vpAndScissor.scissorX + vpAndScissor.scissorW; + scissor.bottom = vpAndScissor.scissorY + vpAndScissor.scissorH; + context_->RSSetScissorRects(0, &scissor); + */ if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index c418e31786..3fbe3479d7 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -57,7 +57,7 @@ #define TEXCACHE_MIN_PRESSURE 16 * 1024 * 1024 // Total in VRAM #define TEXCACHE_SECOND_MIN_PRESSURE 4 * 1024 * 1024 -static const D3D11_INPUT_ELEMENT_DESC g_FramebufferVertexElements[] = { +static const D3D11_INPUT_ELEMENT_DESC g_QuadVertexElements[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12,}, }; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 04b568b6f5..a22737938b 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -1021,7 +1021,7 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2; const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2; if (sameSize && sameDepth && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) { - draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1); + draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT); return; } } diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 2f3eec4aac..c88309eb9f 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -582,7 +582,7 @@ public: // Copies data from the CPU over into the buffer, at a specific offset. This does not change the size of the buffer and cannot write outside it. virtual void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) = 0; - virtual void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) = 0; + virtual void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) = 0; virtual bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) = 0; // These functions should be self explanatory. diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 67c36080c2..3d7587dd81 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -45,7 +45,7 @@ public: void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; - void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) override; bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; // These functions should be self explanatory. @@ -1117,18 +1117,41 @@ void D3D11DrawContext::Clear(int mask, uint32_t colorval, float depthVal, int st } } -void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) { +void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) { D3D11Framebuffer *src = (D3D11Framebuffer *)srcfb; D3D11Framebuffer *dst = (D3D11Framebuffer *)dstfb; - // CopySubResource ? + ID3D11Texture2D *srcTex = nullptr; + ID3D11Texture2D *dstTex = nullptr; + switch (channelBits) { + case FB_COLOR_BIT: + srcTex = src->colorTex; + dstTex = dst->colorTex; + break; + case FB_DEPTH_BIT: + srcTex = src->depthStencilTex; + dstTex = dst->depthStencilTex; + break; + } + + // TODO: Check for level too! + if (width == src->width && width == dst->width && height == src->height && height == dst->height && x == 0 && y == 0 && z == 0 && dstX == 0 && dstY == 0 && dstZ == 0) { + // Don't need to specify region. This might be faster, too. + context_->CopyResource(dstTex, srcTex); + return; + } + + D3D11_BOX srcBox{ + x, y, z, x+width, y+height, z+depth + }; + context_->CopySubresourceRegion(dstTex, dstLevel, dstX, dstY, dstZ, srcTex, level, &srcBox); } bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { D3D11Framebuffer *src = (D3D11Framebuffer *)srcfb; D3D11Framebuffer *dst = (D3D11Framebuffer *)dstfb; - // Unfortunately D3D11 has no equivalent to this, gotta render a quad. + // Unfortunately D3D11 has no equivalent to this, gotta render a quad. Well, in some cases we can issue a copy instead. return true; } diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index 811e7d0a2a..7b75b759a0 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -478,7 +478,7 @@ public: void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; - void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) override {} + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) override {} bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; // These functions should be self explanatory. diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index b3fba72245..30c2539f4a 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -469,7 +469,7 @@ public: void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; - void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) override; bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; // These functions should be self explanatory. @@ -1506,29 +1506,41 @@ void OpenGLContext::BindFramebufferForRead(Framebuffer *fbo) { fbo_bind_fb_target(true, fb->handle); } -void OpenGLContext::CopyFramebufferImage(Framebuffer *fbsrc, int srcLevel, int srcX, int srcY, int srcZ, Framebuffer *fbdst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) { +void OpenGLContext::CopyFramebufferImage(Framebuffer *fbsrc, int srcLevel, int srcX, int srcY, int srcZ, Framebuffer *fbdst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) { OpenGLFramebuffer *src = (OpenGLFramebuffer *)fbsrc; OpenGLFramebuffer *dst = (OpenGLFramebuffer *)fbdst; + GLuint srcTex = 0; + GLuint dstTex = 0; + switch (channelBits) { + case FB_COLOR_BIT: + srcTex = src->color_texture; + dstTex = dst->color_texture; + break; + case FB_DEPTH_BIT: + srcTex = src->z_buffer ? src->z_buffer : src->z_stencil_buffer; + dstTex = dst->z_buffer ? dst->z_buffer : dst->z_stencil_buffer; + break; + } #if defined(USING_GLES2) #ifndef IOS glCopyImageSubDataOES( - src->color_texture, GL_TEXTURE_2D, srcLevel, srcX, srcY, srcZ, - dst->color_texture, GL_TEXTURE_2D, dstLevel, dstX, dstY, dstZ, + srcTex, GL_TEXTURE_2D, srcLevel, srcX, srcY, srcZ, + dstTex, GL_TEXTURE_2D, dstLevel, dstX, dstY, dstZ, width, height, depth); return; #endif #else if (gl_extensions.ARB_copy_image) { glCopyImageSubData( - src->color_texture, GL_TEXTURE_2D, srcLevel, srcX, srcY, srcZ, - dst->color_texture, GL_TEXTURE_2D, dstLevel, dstX, dstY, dstZ, + srcTex, GL_TEXTURE_2D, srcLevel, srcX, srcY, srcZ, + dstTex, GL_TEXTURE_2D, dstLevel, dstX, dstY, dstZ, width, height, depth); return; } else if (gl_extensions.NV_copy_image) { // Older, pre GL 4.x NVIDIA cards. glCopyImageSubDataNV( - src->color_texture, GL_TEXTURE_2D, srcLevel, srcX, srcY, srcZ, - dst->color_texture, GL_TEXTURE_2D, dstLevel, dstX, dstY, dstZ, + srcTex, GL_TEXTURE_2D, srcLevel, srcX, srcY, srcZ, + dstTex, GL_TEXTURE_2D, dstLevel, dstX, dstY, dstZ, width, height, depth); return; } diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index c57058cec8..16f34b814e 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -340,7 +340,7 @@ public: void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; - void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) override; bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; // These functions should be self explanatory. @@ -1280,17 +1280,34 @@ Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { return fb; } -void VKContext::CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) {} -bool VKContext::BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { return true; } +void VKContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits) { + VKFramebuffer *src = (VKFramebuffer *)srcfb; + VKFramebuffer *dst = (VKFramebuffer *)dstfb; +} +bool VKContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { + VKFramebuffer *src = (VKFramebuffer *)srcfb; + VKFramebuffer *dst = (VKFramebuffer *)dstfb; + return true; +} // These functions should be self explanatory. -void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo) {} +void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo) { + VKFramebuffer *fb = (VKFramebuffer *)fbo; +} // color must be 0, for now. -void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) {} -void VKContext::BindFramebufferForRead(Framebuffer *fbo) {} +void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) { + VKFramebuffer *fb = (VKFramebuffer *)fbo; -void VKContext::BindBackbufferAsRenderTarget() {} -uintptr_t VKContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) { return 0; } +} +void VKContext::BindFramebufferForRead(Framebuffer *fbo) { /* noop */ } + +void VKContext::BindBackbufferAsRenderTarget() { + +} + +uintptr_t VKContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) { + return 0; +} void VKContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { VKFramebuffer *fb = (VKFramebuffer *)fbo; From 4fbb537c920d519e3e124d35bd90808bda17b914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 12:02:13 +0100 Subject: [PATCH 20/40] Assorted D3D11 fixes --- GPU/Common/ShaderUniforms.cpp | 2 +- GPU/D3D11/DrawEngineD3D11.cpp | 2 ++ GPU/D3D11/TextureCacheD3D11.cpp | 8 ++++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index e5acc7bc27..82cdc70b33 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -15,7 +15,7 @@ static void ConvertProjMatrixToVulkan(Matrix4x4 &in) { static void ConvertProjMatrixToD3D11(Matrix4x4 &in) { const Vec3 trans(0, 0, gstate_c.vpZOffset * 0.5f + 0.5f); - const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); + const Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); in.translateAndScale(trans, scale); } diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index a03cdc6139..d136b93822 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -772,6 +772,8 @@ rotateVBO: ID3D11InputLayout *inputLayout = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); + shaderManager_->UpdateUniforms(); + shaderManager_->BindUniforms(); context_->IASetInputLayout(inputLayout); UINT stride = dec_->GetDecVtxFmt().stride; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 3fbe3479d7..77c89f036f 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -1137,10 +1137,12 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & gpuStats.numTexturesDecoded++; // For UpdateSubresource, we can't decode directly into the texture so we allocate a buffer :( - u32 *mapData = new u32[w * h]{}; - int mapRowPitch = w * 4; + u32 *mapData; + int mapRowPitch; if (replaced.GetSize(level, w, h)) { + mapData = new u32[w * h]{}; + mapRowPitch = w * 4; replaced.Load(level, mapData, mapRowPitch); dstFmt = ToDXGIFormat(replaced.Format(level)); } else { @@ -1149,6 +1151,8 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & u32 texaddr = gstate.getTextureAddress(level); int bufw = GetTextureBufw(level, texaddr, tfmt); int bpp = dstFmt == DXGI_FORMAT_R8G8B8A8_UNORM ? 4 : 2; + mapRowPitch = std::max(bufw, w) * 4; + mapData = new u32[mapRowPitch / 4 * h]{}; u32 *pixelData = (u32 *)mapData; int decPitch = mapRowPitch; From 07c88ef2b0d95c42461449cc5cff40749182042d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 12:07:37 +0100 Subject: [PATCH 21/40] D3D11: Fix reverse colors in drawpixels, fix a potential crash --- GPU/D3D11/FramebufferManagerD3D11.cpp | 5 ++--- ext/native/thin3d/thin3d_d3d11.cpp | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 4b47dfa89e..f7d1179ae6 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -206,7 +206,6 @@ void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferForm convBuf = (u8*)map.pData; - // Final format is BGRA(directx) if (srcPixelFormat != GE_FORMAT_8888 || srcStride != 512) { for (int y = 0; y < height; y++) { switch (srcPixelFormat) { @@ -237,7 +236,7 @@ void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferForm { const u32_le *src = (const u32_le *)srcPixels + srcStride * y; u32 *dst = (u32 *)(convBuf + map.RowPitch * y); - ConvertRGBA8888ToBGRA8888(dst, src, width); + memcpy(dst, src, width * 4); } break; } @@ -246,7 +245,7 @@ void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferForm for (int y = 0; y < height; y++) { const u32_le *src = (const u32_le *)srcPixels + srcStride * y; u32 *dst = (u32 *)(convBuf + map.RowPitch * y); - ConvertRGBA8888ToBGRA8888(dst, src, width); + memcpy(dst, src, width * 4); } } diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 3d7587dd81..7eaf004e3b 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -1102,12 +1102,12 @@ void D3D11DrawContext::BindSamplerStates(int start, int count, SamplerState **st } void D3D11DrawContext::Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) { - if (mask & ClearFlag::COLOR) { + if ((mask & ClearFlag::COLOR) && curRenderTargetView_) { float colorRGBA[4]; Uint8x4ToFloat4(colorRGBA, colorval); context_->ClearRenderTargetView(curRenderTargetView_, colorRGBA); } - if (mask & (ClearFlag::DEPTH | ClearFlag::STENCIL)) { + if ((mask & (ClearFlag::DEPTH | ClearFlag::STENCIL)) && curDepthStencilView_) { UINT clearFlag = 0; if (mask & ClearFlag::DEPTH) clearFlag |= D3D11_CLEAR_DEPTH; From 6efdde9ea4e18d0f1321fda33d2baba70e3b1185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 12:12:15 +0100 Subject: [PATCH 22/40] D3D11: Fix build issue in Release mode. Triangle fan workaround. --- GPU/Common/FramebufferCommon.cpp | 1 + GPU/D3D11/DrawEngineD3D11.cpp | 6 ++---- Windows/GPU/D3D11Context.cpp | 4 +--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index f6b7e5e17f..e4dc209d32 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -567,6 +567,7 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe textureCache_->ForgetLastTexture(); if (useBufferedRendering_) { + if (vfb->fbo) { draw_->BindFramebufferAsRenderTarget(vfb->fbo); } else { diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index d136b93822..d304c7ad31 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -587,8 +587,6 @@ void DrawEngineD3D11::DoFlush() { if (useHWTransform) { ID3D11Buffer *vb_ = nullptr; ID3D11Buffer *ib_ = nullptr; - if (prim == GE_PRIM_TRIANGLE_FAN) - Crash(); int vertexCount = 0; int maxIndex = 0; @@ -676,7 +674,7 @@ void DrawEngineD3D11::DoFlush() { vai->prim = indexGen.Prim(); vai->maxIndex = indexGen.MaxIndex(); vai->flags = gstate_c.vertexFullAlpha ? VAI11_FLAG_VERTEXFULLALPHA : 0; - useElements = !indexGen.SeenOnlyPurePrims(); + useElements = !indexGen.SeenOnlyPurePrims() || prim == GE_PRIM_TRIANGLE_FAN; if (!useElements && indexGen.PureCount()) { vai->numVerts = indexGen.PureCount(); } @@ -747,7 +745,7 @@ void DrawEngineD3D11::DoFlush() { DecodeVerts(); rotateVBO: gpuStats.numUncachedVertsDrawn += indexGen.VertexCount(); - useElements = !indexGen.SeenOnlyPurePrims(); + useElements = !indexGen.SeenOnlyPurePrims() || prim == GE_PRIM_TRIANGLE_FAN; vertexCount = indexGen.VertexCount(); maxIndex = indexGen.MaxIndex(); if (!useElements && indexGen.PureCount()) { diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index eb12c1f65c..aa4ae704a8 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -120,12 +120,10 @@ void D3D11Context::Shutdown() { d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, false); d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, false); d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, false); -#endif -#ifdef _DEBUG d3dDebug_->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL); -#endif d3dDebug_->Release(); d3dInfoQueue_->Release(); +#endif context_->Release(); context_ = nullptr; From bbdb0ee195a860a4afd460f6d0562f53ab7bba97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 13:55:49 +0100 Subject: [PATCH 23/40] Fix the stencil buffer initialization stuff (not sure it's 100% working et) --- GPU/D3D11/DepalettizeShaderD3D11.cpp | 1 - GPU/D3D11/DrawEngineD3D11.cpp | 19 +++--- GPU/D3D11/FramebufferManagerD3D11.cpp | 50 ++++++--------- GPU/D3D11/FramebufferManagerD3D11.h | 26 ++++---- GPU/D3D11/StencilBufferD3D11.cpp | 87 +++++++++++++++------------ Windows/GPU/D3D11Context.cpp | 2 +- 6 files changed, 87 insertions(+), 98 deletions(-) diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp index b524922d37..216dd7e05e 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.cpp +++ b/GPU/D3D11/DepalettizeShaderD3D11.cpp @@ -26,7 +26,6 @@ #include "GPU/D3D11/DepalettizeShaderD3D11.h" #include "GPU/D3D11/D3D11Util.h" #include "GPU/Common/DepalettizeShaderCommon.h" -//#include "gfx/d3d9_shader.h" static const int DEPAL_TEXTURE_OLD_AGE = 120; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index d304c7ad31..a85241956b 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -846,18 +846,17 @@ rotateVBO: ApplyDrawStateLate(result.setStencil, result.stencilValue); - D3D11VertexShader *vshader; - D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false); - context_->PSSetShader(fshader->GetShader(), nullptr, 0); - context_->VSSetShader(vshader->GetShader(), nullptr, 0); - shaderManager_->UpdateUniforms(); - shaderManager_->BindUniforms(); - if (result.action == SW_DRAW_PRIMITIVES) { const int vertexSize = sizeof(transformed[0]); - // This is so weird. Why do we need the shader bytecode to create an input layout?? + D3D11VertexShader *vshader; + D3D11FragmentShader *fshader; + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false); + context_->PSSetShader(fshader->GetShader(), nullptr, 0); + context_->VSSetShader(vshader->GetShader(), nullptr, 0); + shaderManager_->UpdateUniforms(); + shaderManager_->BindUniforms(); + // We really do need a vertex layout for each vertex shader (or at least check its ID bits for what inputs it uses)! // Some vertex shaders ignore one of the inputs, and then the layout created from it will lack it, which will be a problem for others. InputLayoutKey key{ 0xFFFFFFFF, vshader }; // Let's use 0xFFFFFFFF to signify TransformedVertex @@ -881,7 +880,7 @@ rotateVBO: context_->IASetVertexBuffers(0, 1, &buf, &stride, &vOffset); if (drawIndexed) { UINT iOffset; - int iSize = sizeof(int16_t) * numTrans; + int iSize = sizeof(uint16_t) * numTrans; uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize); memcpy(iptr, inds, iSize); pushInds_->EndPush(context_); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index f7d1179ae6..b195f36245 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -71,19 +71,13 @@ static const char *pscode = " return c;\n" "}\n"; -static const D3D11_INPUT_ELEMENT_DESC g_QuadVertexElements[] = { +const D3D11_INPUT_ELEMENT_DESC FramebufferManagerD3D11::g_QuadVertexElements[2] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, }, }; FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) - : FramebufferManagerCommon(draw), - drawPixelsTex_(0), - convBuf(0), - stencilUploadPS_(nullptr), - stencilUploadVS_(nullptr), - stencilUploadFailed_(false) { - + : FramebufferManagerCommon(draw) { device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE); context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); @@ -92,7 +86,7 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) std::string errorMsg; quadVertexShader_ = CreateVertexShaderD3D11(device_, vscode, strlen(vscode), &bytecode); quadPixelShader_ = CreatePixelShaderD3D11(device_, pscode, strlen(pscode)); - device_->CreateInputLayout(g_QuadVertexElements, ARRAY_SIZE(g_QuadVertexElements), bytecode.data(), bytecode.size(), &quadVertexDecl_); + device_->CreateInputLayout(g_QuadVertexElements, ARRAY_SIZE(g_QuadVertexElements), bytecode.data(), bytecode.size(), &quadInputLayout_); // STRIP geometry static const float fsCoord[20] = { @@ -115,27 +109,19 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) FramebufferManagerD3D11::~FramebufferManagerD3D11() { // Drawing cleanup - if (vbFullScreenRect_) { - vbFullScreenRect_->Release(); - } - if (quadVertexShader_) { + if (quadVertexShader_) quadVertexShader_->Release(); - quadVertexShader_ = nullptr; - } - if (quadPixelShader_) { + if (quadPixelShader_) quadPixelShader_->Release(); - quadPixelShader_ = nullptr; - } - quadVertexDecl_->Release(); - if (drawPixelsTex_) { - drawPixelsTex_->Release(); - } - if (drawPixelsTexView_) { - drawPixelsTexView_->Release(); - } + quadInputLayout_->Release(); quadBuffer_->Release(); fsQuadBuffer_->Release(); + if (drawPixelsTex_) + drawPixelsTex_->Release(); + if (drawPixelsTexView_) + drawPixelsTexView_->Release(); + // FBO cleanup for (auto it = tempFBOs_.begin(), end = tempFBOs_.end(); it != end; ++it) { delete it->second.fbo; @@ -147,12 +133,12 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() { if (stencilMaskStates_[i]) stencilMaskStates_[i]->Release(); } - if (stencilUploadPS_) { + if (stencilUploadPS_) stencilUploadPS_->Release(); - } - if (stencilUploadVS_) { + if (stencilUploadVS_) stencilUploadVS_->Release(); - } + if (stencilUploadInputLayout_) + stencilUploadInputLayout_->Release(); } void FramebufferManagerD3D11::SetTextureCache(TextureCacheD3D11 *tc) { @@ -338,7 +324,7 @@ void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float context_->RSSetState(stockD3D11.rasterStateNoCull); context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], nullptr, 0xFFFFFFFF); context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0); - context_->IASetInputLayout(quadVertexDecl_); + context_->IASetInputLayout(quadInputLayout_); context_->PSSetShader(quadPixelShader_, 0, 0); context_->VSSetShader(quadVertexShader_, 0, 0); context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); @@ -379,10 +365,10 @@ void FramebufferManagerD3D11::ReformatFramebufferFrom(VirtualFramebuffer *vfb, G context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0], nullptr, 0xFFFFFFFF); context_->RSSetState(stockD3D11.rasterStateNoCull); - context_->IASetInputLayout(quadVertexDecl_); + context_->IASetInputLayout(quadInputLayout_); context_->PSSetShader(quadPixelShader_, nullptr, 0); context_->VSSetShader(quadVertexShader_, nullptr, 0); - context_->IASetVertexBuffers(0, 1, &vbFullScreenRect_, &vbFullScreenStride_, &vbFullScreenOffset_); + context_->IASetVertexBuffers(0, 1, &fsQuadBuffer_, &quadStride_, &quadOffset_); shaderManager_->DirtyLastShader(); D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }; context_->RSSetViewports(1, &vp); diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 18c6ab359d..409e2157d2 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -105,35 +105,33 @@ private: ID3D11DeviceContext *context_; // Used by DrawPixels - ID3D11Texture2D *drawPixelsTex_; - ID3D11ShaderResourceView *drawPixelsTexView_; - int drawPixelsTexW_; - int drawPixelsTexH_; + ID3D11Texture2D *drawPixelsTex_ = nullptr; + ID3D11ShaderResourceView *drawPixelsTexView_ = nullptr; + int drawPixelsTexW_ = 0; + int drawPixelsTexH_ = 0; ID3D11VertexShader *quadVertexShader_; ID3D11PixelShader *quadPixelShader_; - ID3D11InputLayout *quadVertexDecl_; + ID3D11InputLayout *quadInputLayout_; // Dynamic ID3D11Buffer *quadBuffer_; ID3D11Buffer *fsQuadBuffer_; + const UINT quadStride_ = 20; + const UINT quadOffset_ = 0; + static const D3D11_INPUT_ELEMENT_DESC g_QuadVertexElements[2]; - u8 *convBuf; + u8 *convBuf = nullptr; int plainColorLoc_; - ID3D11PixelShader *stencilUploadPS_; - ID3D11VertexShader *stencilUploadVS_; - ID3D11InputLayout *stencilUploadInputLayout_; + ID3D11PixelShader *stencilUploadPS_ = nullptr; + ID3D11VertexShader *stencilUploadVS_ = nullptr; + ID3D11InputLayout *stencilUploadInputLayout_ = nullptr; ID3D11DepthStencilState *stencilMaskStates_[256]{}; - bool stencilUploadFailed_; TextureCacheD3D11 *textureCacheD3D11_; ShaderManagerD3D11 *shaderManager_; DrawEngineD3D11 *drawEngine_; - ID3D11Buffer *vbFullScreenRect_ = nullptr; - UINT vbFullScreenStride_ = 20; - UINT vbFullScreenOffset_ = 0; - // Used by post-processing shader std::vector extraFBOs_; diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp index a674b36494..8aaa3927d5 100644 --- a/GPU/D3D11/StencilBufferD3D11.cpp +++ b/GPU/D3D11/StencilBufferD3D11.cpp @@ -36,7 +36,8 @@ struct StencilUB { }; static const char *stencil_ps = -"sampler tex: register(s0);\n" +"SamplerState samp : register(s0);\n" +"Texture2D tex : register(t0);\n" "cbuffer base : register(b0) {\n" " float4 u_stencilValue;\n" "};\n" @@ -44,8 +45,8 @@ static const char *stencil_ps = " float2 v_texcoord0 : TEXCOORD0;\n" "};\n" "float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n" -"float4 main(PS_IN In) : COLOR {\n" -" float4 index = tex2D(tex, In.v_texcoord0);\n" +"float4 main(PS_IN In) : SV_Target {\n" +" float4 index = tex.Sample(samp, In.v_texcoord0);\n" " float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue.x);\n" " clip(fmod(floor(shifted), 2.0) - 0.99);\n" " return index.aaaa;\n" @@ -57,8 +58,8 @@ static const char *stencil_vs = " float2 a_texcoord0 : TEXCOORD0;\n" "};\n" "struct VS_OUT {\n" -" float4 position : POSITION;\n" " float2 v_texcoord0 : TEXCOORD0;\n" +" float4 position : SV_Position;\n" "};\n" "VS_OUT main(VS_IN In) {\n" " VS_OUT Out;\n" @@ -152,21 +153,16 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ return false; } - /* - // TODO: Find a fast way to clear stencil+alpha. Probably a quad. - // Let's not bother with the shader if it's just zero. - dxstate.scissorTest.disable(); - dxstate.colorMask.set(false, false, false, true); - // TODO: Verify this clears only stencil/alpha. - pD3Ddevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0, 0, 0, 0), 0.0f, 0); - */ + // Clear stencil+alpha but not color. Only way is to draw a quad. + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF); + context_->RSSetState(stockD3D11.rasterStateNoCull); + context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0); + context_->IASetVertexBuffers(0, 1, &fsQuadBuffer_, &quadStride_, &quadOffset_); + context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context_->Draw(4, 0); return true; } - if (stencilUploadFailed_) { - return false; - } - // TODO: Helper with logging? if (!stencilUploadPS_) { std::string errorMessage; @@ -176,11 +172,7 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ std::string errorMessage; std::vector byteCode; stencilUploadVS_ = CreateVertexShaderD3D11(device_, stencil_vs, strlen(stencil_vs), &byteCode); - // stencilUploadInputLayout_ = device_->CreateInputLayout() - } - if (!stencilUploadPS_ || !stencilUploadVS_) { - stencilUploadFailed_ = true; - return false; + device_->CreateInputLayout(g_QuadVertexElements, 2, byteCode.data(), byteCode.size(), &stencilUploadInputLayout_); } shaderManager_->DirtyLastShader(); @@ -222,40 +214,55 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ coord[i * 5 + 1] = -(coord[i * 5 + 1] * invDestH - 1.0f); } - /* TODO - // context_->IASetInputLayout(ia); - context_->PSSetShader(stencilUploadPS_); - context_->VSSetSamplers(stencilUploadVS_); - context_->pD3Ddevice->SetTexture(0, drawPixelsTex_); + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(quadBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, coord, sizeof(float) * 4 * 5); + context_->Unmap(quadBuffer_, 0); shaderManager_->DirtyLastShader(); textureCacheD3D11_->ForgetLastTexture(); + context_->IASetInputLayout(stencilUploadInputLayout_); + context_->PSSetShader(stencilUploadPS_, nullptr, 0); + context_->VSSetShader(stencilUploadVS_, nullptr, 0); + context_->PSSetShaderResources(0, 1, &drawPixelsTexView_); + context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context_->RSSetState(stockD3D11.rasterStateNoCull); + context_->IASetVertexBuffers(0, 1, &quadBuffer_, &quadStride_, &quadOffset_); + for (int i = 1; i < values; i += i) { if (!(usedBits & i)) { // It's already zero, let's skip it. continue; } + uint8_t mask = 0; + uint8_t value = 0; if (dstBuffer->format == GE_FORMAT_4444) { - dxstate.stencilMask.set(i | (i << 4)); - const float f[4] = {i * (16.0f / 255.0f)}; - pD3Ddevice->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); + mask = i | (i << 4); + value = i * 16; } else if (dstBuffer->format == GE_FORMAT_5551) { - dxstate.stencilMask.set(0xFF); - const float f[4] = {i * (128.0f / 255.0f)}; - pD3Ddevice->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); + mask = 0xFF; + value = i * 128; } else { - dxstate.stencilMask.set(i); - const float f[4] = {i * (1.0f / 255.0f)}; - pD3Ddevice->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); + mask = i; + value = i; } - HRESULT hr = pD3Ddevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coord, 5 * sizeof(float)); - if (FAILED(hr)) { - ERROR_LOG_REPORT(G3D, "Failed to draw stencil bit %x: %08x", i, hr); + if (!stencilMaskStates_[mask]) { + D3D11_DEPTH_STENCIL_DESC desc{}; + desc.DepthEnable = false; + desc.StencilEnable = true; + desc.StencilReadMask = 0xFF; + desc.StencilWriteMask = mask; + desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; + desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + desc.BackFace = desc.FrontFace; + device_->CreateDepthStencilState(&desc, &stencilMaskStates_[mask]); } + context_->OMSetDepthStencilState(stencilMaskStates_[mask], value); + context_->Draw(4, 0); } - dxstate.stencilMask.set(0xFF); RebindFramebuffer(); - */ return true; } diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index aa4ae704a8..cdd773dbe6 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -78,7 +78,7 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { if (SUCCEEDED(d3dDebug_->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&d3dInfoQueue_))) { d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); - d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true); + //d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true); } } #endif From 05bdf8abbfc13cd28a08f07f62e4550a8e81cc9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 14:11:14 +0100 Subject: [PATCH 24/40] Windows GEDebugger: Make display list view DPI-aware for easier debugging on high-dpi screens --- Windows/GEDebugger/CtrlDisplayListView.cpp | 18 +++++++++++------- Windows/GEDebugger/CtrlDisplayListView.h | 1 - 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Windows/GEDebugger/CtrlDisplayListView.cpp b/Windows/GEDebugger/CtrlDisplayListView.cpp index 26086144ba..7b71b7f3f1 100644 --- a/Windows/GEDebugger/CtrlDisplayListView.cpp +++ b/Windows/GEDebugger/CtrlDisplayListView.cpp @@ -1,3 +1,4 @@ +#include "base/display.h" #include "Windows/GEDebugger/CtrlDisplayListView.h" #include "Windows/GEDebugger/GEDebugger.h" #include "Windows/InputBox.h" @@ -43,12 +44,15 @@ CtrlDisplayListView::CtrlDisplayListView(HWND _wnd) SetScrollRange(wnd, SB_VERT, -1,1,TRUE); instructionSize = 4; - rowHeight = g_Config.iFontHeight+2; - charWidth = g_Config.iFontWidth; - font = CreateFont(rowHeight-2,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH, + int fontHeight = g_Config.iFontHeight / g_dpi_scale; + int charWidth = g_Config.iFontWidth / g_dpi_scale; + + rowHeight = fontHeight +2; + + font = CreateFont(fontHeight,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH, L"Lucida Console"); - boldfont = CreateFont(rowHeight-2,charWidth,0,0,FW_DEMIBOLD,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH, + boldfont = CreateFont(fontHeight,charWidth,0,0,FW_DEMIBOLD,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH, L"Lucida Console"); pixelPositions.addressStart = 16; @@ -58,9 +62,9 @@ CtrlDisplayListView::CtrlDisplayListView(HWND _wnd) validDisplayList = false; } -CtrlDisplayListView::~CtrlDisplayListView() -{ - +CtrlDisplayListView::~CtrlDisplayListView() { + DeleteObject(font); + DeleteObject(boldfont); } CtrlDisplayListView *CtrlDisplayListView::getFrom(HWND hwnd) diff --git a/Windows/GEDebugger/CtrlDisplayListView.h b/Windows/GEDebugger/CtrlDisplayListView.h index d8e79498a1..5f9748fb4a 100644 --- a/Windows/GEDebugger/CtrlDisplayListView.h +++ b/Windows/GEDebugger/CtrlDisplayListView.h @@ -20,7 +20,6 @@ class CtrlDisplayListView u32 selectRangeEnd; int visibleRows; - int charWidth; int rowHeight; int instructionSize; bool hasFocus; From 4f2fb10347a52be612fb79a32f954168451e99da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 16:14:14 +0100 Subject: [PATCH 25/40] Further D3D11 fixes --- GPU/Common/ShaderUniforms.h | 2 +- GPU/Common/SoftwareTransformCommon.cpp | 2 +- GPU/D3D11/DrawEngineD3D11.cpp | 23 +++++++++++------------ GPU/Directx9/PixelShaderGeneratorDX9.cpp | 2 +- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 9 +++++++-- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index 17ec2955bb..df3d0e495e 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -69,7 +69,7 @@ R"( float4x4 u_proj; float4x4 u_tex; float4 u_uvscaleoffset; float4 u_depthRange; - float3 u_fogcoef; + float3 u_fogcoef_stencilreplace; float4 u_matambientalpha; float3 u_fogcolor; float3 u_texenv; diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 5d9c2cf4c7..bab715e13f 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -502,7 +502,7 @@ void SoftwareTransform( const u16 *indsIn = (const u16 *)inds; u16 *newInds = inds + vertexCount; u16 *indsOut = newInds; - maxIndex = 4 * vertexCount; + maxIndex = 4 * (vertexCount / 2); for (int i = 0; i < vertexCount; i += 2) { const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]]; const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]]; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index a85241956b..4b994a6c61 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -40,13 +40,13 @@ #include "GPU/D3D11/ShaderManagerD3D11.h" #include "GPU/D3D11/GPU_D3D11.h" -const D3D11_PRIMITIVE_TOPOLOGY glprim[8] = { +const D3D11_PRIMITIVE_TOPOLOGY d3d11prim[8] = { D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, D3D11_PRIMITIVE_TOPOLOGY_LINELIST, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, - D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED, // Fans not supported + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Fans not supported D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Need expansion - though we could do it with geom shaders in most cases }; @@ -104,7 +104,9 @@ DrawEngineD3D11::DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, tessDataTransfer = new TessellationDataTransferD3D11(); - // Vertex pushing buffers. + // Vertex pushing buffers. For uniforms we use short DISCARD buffers, but we could use + // this kind of buffer there as well with D3D11.1. We might be able to use the same buffer + // for both vertices and indices, and possibly all three data types. pushVerts_ = new PushBufferD3D11(device, VERTEX_PUSH_SIZE, D3D11_BIND_VERTEX_BUFFER); pushInds_ = new PushBufferD3D11(device, INDEX_PUSH_SIZE, D3D11_BIND_INDEX_BUFFER); } @@ -113,10 +115,8 @@ DrawEngineD3D11::~DrawEngineD3D11() { delete pushVerts_; delete pushInds_; - for (auto decl = inputLayoutMap_.begin(); decl != inputLayoutMap_.end(); ++decl) { - if (decl->second) { - decl->second->Release(); - } + for (auto &decl : inputLayoutMap_) { + decl.second->Release(); } for (auto &depth : depthStencilCache_) { depth.second->Release(); @@ -559,12 +559,10 @@ void DrawEngineD3D11::BeginFrame() { } VertexArrayInfoD3D11::~VertexArrayInfoD3D11() { - if (vbo) { + if (vbo) vbo->Release(); - } - if (ebo) { + if (ebo) ebo->Release(); - } } static uint32_t SwapRB(uint32_t c) { @@ -775,7 +773,7 @@ rotateVBO: context_->IASetInputLayout(inputLayout); UINT stride = dec_->GetDecVtxFmt().stride; - context_->IASetPrimitiveTopology(glprim[prim]); + context_->IASetPrimitiveTopology(d3d11prim[prim]); if (!vb_) { // Push! UINT vOffset; @@ -869,6 +867,7 @@ rotateVBO: layout = iter->second; } context_->IASetInputLayout(layout); + context_->IASetPrimitiveTopology(d3d11prim[prim]); UINT stride = sizeof(TransformedVertex); UINT vOffset = 0; diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/PixelShaderGeneratorDX9.cpp index 382bf440c1..b099d7a0e7 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/PixelShaderGeneratorDX9.cpp @@ -341,7 +341,7 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage if (stencilToAlpha != REPLACE_ALPHA_NO) { switch (replaceAlphaWithStencilType) { case STENCIL_VALUE_UNIFORM: - replacedAlpha = "u_stencilReplaceValue"; + replacedAlpha = lang == HLSL_D3D11 ? "u_fogcoef_stencilreplace.z" : "u_stencilReplaceValue"; break; case STENCIL_VALUE_ZERO: diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index b9ff0f0dd1..37b2c47645 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -604,8 +604,13 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l } // Compute fogdepth - if (enableFog) - WRITE(p, " Out.v_fogdepth.x = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n"); + if (enableFog) { + if (lang == HLSL_D3D11) { + WRITE(p, " Out.v_fogdepth.x = (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, " return Out;\n"); From cb407a4019eb1311cd64304a4e4186aba1afbca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 16:21:24 +0100 Subject: [PATCH 26/40] Minor tweaks --- GPU/D3D11/DrawEngineD3D11.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 4b994a6c61..247bf17b37 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -834,7 +834,7 @@ rotateVBO: params.transformedExpanded = transformedExpanded; params.fbman = framebufferManager_; params.texCache = textureCache_; - params.allowSeparateAlphaClear = true; + params.allowSeparateAlphaClear = false; // D3D11 doesn't support separate alpha clears int maxIndex = indexGen.MaxIndex(); SoftwareTransform( @@ -898,7 +898,7 @@ rotateVBO: if (gstate.isClearModeAlphaMask()) clearFlag |= Draw::STENCIL; if (gstate.isClearModeDepthMask()) clearFlag |= Draw::DEPTH; - if (clearColor) { + if (clearFlag & (Draw::COLOR | Draw::STENCIL)) { framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); } if (clearFlag & Draw::DEPTH) { @@ -911,7 +911,6 @@ rotateVBO: if (clearFlag & Draw::STENCIL) { colorMask |= 8; } - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[colorMask], nullptr, 0xFFFFFFFF); uint8_t clearStencil = clearColor >> 24; draw_->Clear(clearFlag, clearColor, clearDepth, clearStencil); From 3b12ac5f05e6f55272f1f2c31c0ddba2e0086857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 16:50:45 +0100 Subject: [PATCH 27/40] D3D11: Stencil and scissor work --- GPU/Common/ShaderUniforms.cpp | 2 +- GPU/D3D11/StateMappingD3D11.cpp | 48 +++++++++++++++++++++----------- GPU/D3D11/StencilBufferD3D11.cpp | 16 +++++------ 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 82cdc70b33..80f4dc0a00 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -105,7 +105,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView float fogcoef_stencil[3] = { getFloat24(gstate.fog1), getFloat24(gstate.fog2), - (float)gstate.getStencilTestRef() + (float)gstate.getStencilTestRef()/255.0f }; if (my_isinf(fogcoef_stencil[1])) { // not really sure what a sensible value might be. diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index ece0497732..48a2638d2f 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -202,12 +202,14 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { if (ApplyShaderBlending()) { // We may still want to do something about stencil -> alpha. ApplyStencilReplaceAndLogicOp(blendState.replaceAlphaWithStencil, blendState); - } else { + } + else { // Until next time, force it off. ResetShaderBlending(); gstate_c.allowShaderBlend = false; } - } else if (blendState.resetShaderBlending) { + } + else if (blendState.resetShaderBlending) { ResetShaderBlending(); } @@ -226,7 +228,8 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { if (blendState.useBlendColor) { dynState.blendColor = blendState.blendColor; } - } else { + } + else { key.blend.blendEnable = false; dynState.useBlendColor = false; } @@ -263,17 +266,20 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { // We override this value in the pipeline from software transform for clear rectangles. dynState.stencilRef = 0xFF; key.depthStencil.stencilWriteMask = 0xFF; - } else { + } + else { key.depthStencil.stencilTestEnable = false; dynState.useStencil = false; } - } else { + } + else { if (gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { // Logic Ops if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) { key.blend.logicOpEnable = true; // key.blendKey.logicOp = logicOps[gstate.getLogicOp()]; - } else { + } + else { key.blend.logicOpEnable = false; } } @@ -290,7 +296,8 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { if (gstate.isDepthWriteEnabled()) { framebufferManager_->SetDepthUpdated(); } - } else { + } + else { key.depthStencil.depthTestEnable = false; key.depthStencil.depthWriteEnable = false; key.depthStencil.depthCompareOp = D3D11_COMPARISON_ALWAYS; @@ -320,7 +327,8 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { // Let's not write to alpha if stencil isn't enabled. if (!gstate.isStencilTestEnabled()) { amask = false; - } else { + } + else { // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel. if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_KEEP) { amask = false; @@ -343,7 +351,8 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { key.depthStencil.stencilWriteMask = stencilState.writeMask; dynState.useStencil = true; dynState.stencilRef = stencilState.testRef; - } else { + } + else { key.depthStencil.stencilTestEnable = false; dynState.useStencil = false; } @@ -378,14 +387,21 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } context_->RSSetViewports(1, &vp); - /* D3D11_RECT &scissor = dynState.scissor; - scissor.left = vpAndScissor.scissorX; - scissor.top = vpAndScissor.scissorY; - scissor.right = vpAndScissor.scissorX + vpAndScissor.scissorW; - scissor.bottom = vpAndScissor.scissorY + vpAndScissor.scissorH; - context_->RSSetScissorRects(0, &scissor); - */ + if (vpAndScissor.scissorEnable) { + scissor.left = vpAndScissor.scissorX; + scissor.top = vpAndScissor.scissorY; + scissor.right = vpAndScissor.scissorX + vpAndScissor.scissorW; + scissor.bottom = vpAndScissor.scissorY + vpAndScissor.scissorH; + } + else { + scissor.left = 0; + scissor.top = 0; + scissor.right = framebufferManager_->GetRenderWidth(); + scissor.bottom = framebufferManager_->GetRenderHeight(); + } + context_->RSSetScissorRects(1, &scissor); + if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) { textureCache_->SetTexture(); gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp index 8aaa3927d5..2c8878f2a8 100644 --- a/GPU/D3D11/StencilBufferD3D11.cpp +++ b/GPU/D3D11/StencilBufferD3D11.cpp @@ -177,23 +177,17 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ shaderManager_->DirtyLastShader(); - DisableState(); - - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF); - context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); - context_->RSSetState(stockD3D11.rasterStateNoCull); - u16 w = dstBuffer->renderWidth; u16 h = dstBuffer->renderHeight; - + MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight); if (dstBuffer->fbo) { draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo); + } else { + // something is wrong... } D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }; context_->RSSetViewports(1, &vp); - MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight); - // Zero stencil draw_->Clear(Draw::ClearFlag::STENCIL, 0, 0, 0); @@ -222,6 +216,7 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ shaderManager_->DirtyLastShader(); textureCacheD3D11_->ForgetLastTexture(); + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF); context_->IASetInputLayout(stencilUploadInputLayout_); context_->PSSetShader(stencilUploadPS_, nullptr, 0); context_->VSSetShader(stencilUploadVS_, nullptr, 0); @@ -229,6 +224,9 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); context_->RSSetState(stockD3D11.rasterStateNoCull); context_->IASetVertexBuffers(0, 1, &quadBuffer_, &quadStride_, &quadOffset_); + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF); + context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); + context_->RSSetState(stockD3D11.rasterStateNoCull); for (int i = 1; i < values; i += i) { if (!(usedBits & i)) { From 328201978f8bff10cbffce3e45de7cbde49435f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 17:10:04 +0100 Subject: [PATCH 28/40] D3D11: Prepare for dual src blending support --- GPU/Common/TextureCacheCommon.h | 1 - GPU/D3D11/GPU_D3D11.cpp | 3 ++- GPU/D3D11/TextureCacheD3D11.cpp | 21 --------------- GPU/Directx9/PixelShaderGeneratorDX9.cpp | 34 +++++++++++++++++------- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 6126c1f0f5..56ea4f3fb1 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -75,7 +75,6 @@ struct SamplerCacheKey { } }; - class FramebufferManagerCommon; class TextureCacheCommon { diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 395e3eee80..50c315b64b 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -506,8 +506,9 @@ void GPU_D3D11::CheckGPUFeatures() { features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; features |= GPU_PREFER_CPU_DOWNLOAD; features |= GPU_SUPPORTS_ACCURATE_DEPTH; - features |= GPU_SUPPORTS_ANISOTROPY; + ///features |= GPU_SUPPORTS_ANISOTROPY; features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; + //features |= GPU_SUPPORTS_DUALSOURCE_BLEND; // features |= GPU_SUPPORTS_ANY_COPY_IMAGE; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 77c89f036f..94ab9d5ce2 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -247,27 +247,6 @@ void TextureCacheD3D11::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheK key.sClamp = sClamp; key.tClamp = tClamp; key.maxLevel = entry.maxLevel; - /* - if (entry.maxLevel != 0) { - if (force || entry.lodBias != lodBias) { - if (gstate_c.Supports(GPU_SUPPORTS_TEXTURE_LOD_CONTROL)) { - GETexLevelMode mode = gstate.getTexLevelMode(); - switch (mode) { - case GE_TEXLEVEL_MODE_AUTO: - // TODO - break; - case GE_TEXLEVEL_MODE_CONST: - // Sigh, LOD_BIAS is not even in ES 3.0.. - break; - case GE_TEXLEVEL_MODE_SLOPE: - // TODO - break; - } - } - entry.lodBias = lodBias; - } - } - */ if (entry.framebuffer) { WARN_LOG_REPORT_ONCE(wrongFramebufAttach, G3D, "Framebuffer still attached in UpdateSamplingParams()?"); diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/PixelShaderGeneratorDX9.cpp index b099d7a0e7..15a75b3464 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/PixelShaderGeneratorDX9.cpp @@ -131,11 +131,20 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage WRITE(p, "};\n"); if (lang == HLSL_DX9) { - WRITE(p, "float4 main( PS_IN In ) : COLOR\n"); + WRITE(p, "float4 main( PS_IN In ) : COLOR {\n"); } else { - WRITE(p, "float4 main( PS_IN In ) : SV_Target\n"); + WRITE(p, "struct PS_OUT {\n"); + if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE) { + WRITE(p, " float4 target : SV_Target0;\n"); + WRITE(p, " float4 target1 : SV_Target1;\n"); + } + else { + WRITE(p, " float4 target : SV_Target;\n"); + } + WRITE(p, "};\n"); + WRITE(p, "PS_OUT main( PS_IN In ) {\n"); + WRITE(p, " PS_OUT outfragment;\n"); } - WRITE(p, "{\n"); if (isModeClear) { // Clear mode does not allow any fancy shading. @@ -375,11 +384,6 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage } switch (stencilToAlpha) { - case REPLACE_ALPHA_DUALSOURCE: - WRITE(p, " v.a = %s;\n", replacedAlpha.c_str()); - // TODO: Output the second color as well using original v.a. - break; - case REPLACE_ALPHA_YES: WRITE(p, " v.a = %s;\n", replacedAlpha.c_str()); break; @@ -401,7 +405,19 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage break; } - WRITE(p, " return v;\n"); + if (lang == HLSL_D3D11) { + if (stencilToAlpha == REPLACE_ALPHA_DUALSOURCE) { + WRITE(p, " outfragment.target = float4(v.rgb, %s);\n", replacedAlpha.c_str()); + WRITE(p, " outfragment.target1 = float4(0.0, 0.0, 0.0, v.a);\n"); + WRITE(p, " return outfragment;\n"); + } + else { + WRITE(p, " outfragment.target = v;\n"); + WRITE(p, " return outfragment;\n"); + } + } else { + WRITE(p, " return v;\n"); + } WRITE(p, "}\n"); return true; } From 142b30836ab315135a8fe6cd1d7d36228b3fcda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 12 Feb 2017 17:50:37 +0100 Subject: [PATCH 29/40] DX9 typo fix in PackDepthBuffer --- GPU/Directx9/FramebufferDX9.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 1b37e4ec13..bb872c1f2f 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -982,7 +982,7 @@ static void DXSetViewport(float x, float y, float w, float h, float minZ, float // TODO: Optimize. for (int yp = 0; yp < h; ++yp) { for (int xp = 0; xp < w; ++xp) { - const int offset = (yp + y) & vfb->z_stride + x + xp; + const int offset = (yp + y) * vfb->z_stride + x + xp; float scaled = FromScaledDepth((packed[offset] & 0x00FFFFFF) * (1.0f / 16777215.0f)); if (scaled <= 0.0f) { 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 30/40] 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(); From 94860b663654405eaba125ac3f797edb594ee758 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 13 Feb 2017 01:22:55 +0100 Subject: [PATCH 31/40] Additional D3D11 fixes --- GPU/D3D11/DrawEngineD3D11.cpp | 13 ++---- GPU/D3D11/DrawEngineD3D11.h | 4 +- GPU/D3D11/FramebufferManagerD3D11.cpp | 2 +- GPU/D3D11/StateMappingD3D11.cpp | 20 +++------ GPU/D3D11/StateMappingD3D11.h | 61 +++++++++++++++++---------- GPU/Directx9/DrawEngineDX9.cpp | 6 +-- ext/native/thin3d/thin3d_d3d11.cpp | 7 ++- 7 files changed, 58 insertions(+), 55 deletions(-) diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 0c6d7e44eb..e16f67c3b0 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -760,7 +760,7 @@ rotateVBO: gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255); } - ApplyDrawStateLate(false, 0); + ApplyDrawStateLate(true, dynState_.stencilRef); D3D11VertexShader *vshader; D3D11FragmentShader *fshader; @@ -898,18 +898,11 @@ rotateVBO: if (gstate.isClearModeAlphaMask()) clearFlag |= Draw::STENCIL; if (gstate.isClearModeDepthMask()) clearFlag |= Draw::DEPTH; - if (clearFlag & (Draw::COLOR | Draw::STENCIL)) { - framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - } if (clearFlag & Draw::DEPTH) { framebufferManager_->SetDepthUpdated(); } - - int colorMask = 0; - if (clearColor) - colorMask |= 7; - if (clearFlag & Draw::STENCIL) { - colorMask |= 8; + if (clearFlag & Draw::COLOR) { + framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); } uint8_t clearStencil = clearColor >> 24; diff --git a/GPU/D3D11/DrawEngineD3D11.h b/GPU/D3D11/DrawEngineD3D11.h index bbf9c2feba..3ce10475d9 100644 --- a/GPU/D3D11/DrawEngineD3D11.h +++ b/GPU/D3D11/DrawEngineD3D11.h @@ -234,8 +234,8 @@ private: UVScale uvScale[MAX_DEFERRED_DRAW_CALLS]; // D3D11 state object caches - std::map blendCache_; - std::map depthStencilCache_; + std::map blendCache_; + std::map depthStencilCache_; std::map rasterCache_; // Keep the depth state between ApplyDrawState and ApplyDrawStateLate diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 096df190c8..7d336f2e99 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -413,7 +413,7 @@ void FramebufferManagerD3D11::BlitFramebufferDepth(VirtualFramebuffer *src, Virt if (matchingDepthBuffer && matchingSize) { // 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); + draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, src->renderWidth, src->renderHeight, 1, Draw::FB_DEPTH_BIT); RebindFramebuffer(); } } diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 51824625c5..e1ad394a9e 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -298,8 +298,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { keys_.depthStencil.stencilWriteMask = stencilState.writeMask; dynState_.useStencil = true; dynState_.stencilRef = stencilState.testRef; - } - else { + } else { keys_.depthStencil.stencilTestEnable = false; dynState_.useStencil = false; } @@ -359,16 +358,11 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { } } - uint32_t blendKey, depthKey, rasterKey; - 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; ID3D11RasterizerState *rs = nullptr; - auto blendIter = blendCache_.find(blendKey); + auto blendIter = blendCache_.find(keys_.blend.value); if (blendIter == blendCache_.end()) { D3D11_BLEND_DESC desc{}; D3D11_RENDER_TARGET_BLEND_DESC &rt = desc.RenderTarget[0]; @@ -381,7 +375,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { rt.DestBlendAlpha = (D3D11_BLEND)keys_.blend.destAlpha; rt.RenderTargetWriteMask = keys_.blend.colorWriteMask; device_->CreateBlendState(&desc, &bs); - blendCache_.insert(std::pair(blendKey, bs)); + blendCache_.insert(std::pair(keys_.blend.value, bs)); } else { bs = blendIter->second; } @@ -390,7 +384,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { Uint8x4ToFloat4(blendColor, dynState_.blendColor); context_->OMSetBlendState(bs, blendColor, 0xFFFFFFFF); - auto depthIter = depthStencilCache_.find(depthKey); + auto depthIter = depthStencilCache_.find(keys_.depthStencil.value); if (depthIter == depthStencilCache_.end()) { D3D11_DEPTH_STENCIL_DESC desc{}; desc.DepthEnable = keys_.depthStencil.depthTestEnable; @@ -405,13 +399,13 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { desc.FrontFace.StencilFunc = (D3D11_COMPARISON_FUNC)keys_.depthStencil.stencilCompareFunc; desc.BackFace = desc.FrontFace; device_->CreateDepthStencilState(&desc, &ds); - depthStencilCache_.insert(std::pair(depthKey, ds)); + depthStencilCache_.insert(std::pair(keys_.depthStencil.value, ds)); } else { ds = depthIter->second; } depthStencilState_ = ds; - auto rasterIter = rasterCache_.find(rasterKey); + auto rasterIter = rasterCache_.find(keys_.raster.value); if (rasterIter == rasterCache_.end()) { D3D11_RASTERIZER_DESC desc{}; desc.CullMode = (D3D11_CULL_MODE)(keys_.raster.cullMode); @@ -419,7 +413,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { desc.ScissorEnable = TRUE; desc.FrontCounterClockwise = TRUE; device_->CreateRasterizerState(&desc, &rs); - rasterCache_.insert(std::pair(rasterKey, rs)); + rasterCache_.insert(std::pair(keys_.raster.value, rs)); } else { rs = rasterIter->second; } diff --git a/GPU/D3D11/StateMappingD3D11.h b/GPU/D3D11/StateMappingD3D11.h index 00a141e718..33505d98dd 100644 --- a/GPU/D3D11/StateMappingD3D11.h +++ b/GPU/D3D11/StateMappingD3D11.h @@ -8,35 +8,50 @@ // (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; + union { + uint64_t value; + struct { + // 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; + union { + uint64_t value; + struct { + // 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 + union { + uint32_t value; + struct { + 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. diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index df14e0d4d7..d68d1d1804 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -869,16 +869,14 @@ rotateVBO: } dxstate.colorMask.set((mask & D3DCLEAR_TARGET) != 0, (mask & D3DCLEAR_TARGET) != 0, (mask & D3DCLEAR_TARGET) != 0, (mask & D3DCLEAR_STENCIL) != 0); - device_->Clear(0, NULL, mask, SwapRB(clearColor), clearDepth, clearColor >> 24); - int scissorX1 = gstate.getScissorX1(); - int scissorY1 = gstate.getScissorY1(); int scissorX2 = gstate.getScissorX2() + 1; int scissorY2 = gstate.getScissorY2() + 1; framebufferManager_->SetSafeSize(scissorX2, scissorY2); - if (g_Config.bBlockTransferGPU && (gstate_c.featureFlags & GPU_USE_CLEAR_RAM_HACK) && gstate.isClearModeColorMask() && (gstate.isClearModeAlphaMask() || gstate.FrameBufFormat() == GE_FORMAT_565)) { + int scissorX1 = gstate.getScissorX1(); + int scissorY1 = gstate.getScissorY1(); ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor); } } diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index a95f2e2ef9..50b8053d21 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -1145,8 +1145,11 @@ void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x return; } - 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); + if (channelBits != FB_DEPTH_BIT) { + // Non-full copies are not supported for the depth channel. + 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); + } } bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { From 373c6ba12f1705d6bf96427ce0ceda4de6838aa6 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 13 Feb 2017 02:07:27 +0100 Subject: [PATCH 32/40] More D3D11 fixes, hopefully without breaking DX9 --- GPU/Common/DepalettizeShaderCommon.cpp | 6 +++--- GPU/Common/ShaderUniforms.cpp | 10 ++++++---- GPU/Common/ShaderUniforms.h | 10 ++++++++-- GPU/D3D11/TextureCacheD3D11.cpp | 2 +- GPU/Directx9/VertexShaderGeneratorDX9.cpp | 8 ++++---- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index 6e1d2f0151..7c0ffa5e72 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -56,8 +56,8 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang } if (language == HLSL_D3D11) { - WRITE(p, "float4 main(in v_texcoord0 : TEXCOORD0) : SV_Target {\n"); - WRITE(p, " float4 color = texSamp.Sample(tex, v_texcoord0);\n"); + WRITE(p, "float4 main(in float2 v_texcoord0 : TEXCOORD0) : SV_Target {\n"); + WRITE(p, " float4 color = tex.Sample(texSamp, v_texcoord0);\n"); } else { // TODO: Add support for integer textures. Though it hardly matters. WRITE(p, "void main() {\n"); @@ -121,7 +121,7 @@ void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLang } if (language == HLSL_D3D11) { - WRITE(p, " fragColor0 = texSamp.Sample(pal, float2((float(index) + 0.5) * (1.0 / %f), 0.0));\n", texturePixels); + WRITE(p, " return pal.Sample(palSamp, float2((float(index) + 0.5) * (1.0 / %f), 0.0));\n", texturePixels); } else { WRITE(p, " fragColor0 = texture(pal, vec2((float(index) + 0.5) * (1.0 / %f), 0.0));\n", texturePixels); } diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 80f4dc0a00..99e56f6721 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -1,3 +1,5 @@ +#include + #include "ShaderUniforms.h" #include "math/dataconv.h" #include "math/lin/matrix4x4.h" @@ -148,7 +150,6 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView if (dirtyUniforms & DIRTY_DEPTHRANGE) { float viewZScale = gstate.getViewportZScale(); float viewZCenter = gstate.getViewportZCenter(); - float viewZInvScale; // We had to scale and translate Z to account for our clamped Z range. // Therefore, we also need to reverse this to round properly. @@ -164,6 +165,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView viewZScale *= (1.0f / gstate_c.vpDepthScale) * 2.0f; viewZCenter -= 65535.0f * gstate_c.vpZOffset + 32768.5f; + float viewZInvScale; if (viewZScale != 0.0) { viewZInvScale = 1.0f / viewZScale; } else { @@ -185,12 +187,12 @@ void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms) { if (dirtyUniforms & DIRTY_MATDIFFUSE) { Uint8x3ToFloat4(ub->materialDiffuse, gstate.materialdiffuse); } + if (dirtyUniforms & DIRTY_MATSPECULAR) { + Uint8x3ToFloat4_Alpha(ub->materialSpecular, gstate.materialspecular, std::max(0.0f, getFloat24(gstate.materialspecularcoef))); + } if (dirtyUniforms & DIRTY_MATEMISSIVE) { Uint8x3ToFloat4(ub->materialEmissive, gstate.materialemissive); } - if (dirtyUniforms & DIRTY_MATSPECULAR) { - Uint8x3ToFloat4_Alpha(ub->materialSpecular, gstate.materialspecular, getFloat24(gstate.materialspecularcoef)); - } for (int i = 0; i < 4; i++) { if (dirtyUniforms & (DIRTY_LIGHT0 << i)) { diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index df3d0e495e..f4e3b81987 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -130,8 +130,14 @@ R"( float4 u_ambient; float3 u_lightatt1; float3 u_lightatt2; float3 u_lightatt3; - float u_lightangle[4]; - float u_lightspotCoef[4]; + float4 u_lightangle0; + float4 u_lightangle1; + float4 u_lightangle2; + float4 u_lightangle3; + float4 u_lightspotCoef0; + float4 u_lightspotCoef1; + float4 u_lightspotCoef2; + float4 u_lightspotCoef3; float3 u_lightambient0; float3 u_lightambient1; float3 u_lightambient2; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 94ab9d5ce2..864660cc7e 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -1142,7 +1142,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & decPitch = w * bpp; } - bool decSuccess = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false); + bool decSuccess = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, true, false); if (!decSuccess) { memset(pixelData, 0, decPitch * h); } diff --git a/GPU/Directx9/VertexShaderGeneratorDX9.cpp b/GPU/Directx9/VertexShaderGeneratorDX9.cpp index c2e9cfbb09..e4b558e75d 100644 --- a/GPU/Directx9/VertexShaderGeneratorDX9.cpp +++ b/GPU/Directx9/VertexShaderGeneratorDX9.cpp @@ -151,8 +151,8 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l if (type == GE_LIGHTTYPE_SPOT || type == GE_LIGHTTYPE_UNKNOWN) { WRITE(p, "float3 u_lightdir%i : register(c%i);\n", i, CONST_VS_LIGHTDIR + i); - WRITE(p, "float u_lightangle%i : register(c%i);\n", i, CONST_VS_LIGHTANGLE + i); - WRITE(p, "float u_lightspotCoef%i : register(c%i);\n", i, CONST_VS_LIGHTSPOTCOEF + i); + WRITE(p, "float4 u_lightangle%i : register(c%i);\n", i, CONST_VS_LIGHTANGLE + i); + WRITE(p, "float4 u_lightspotCoef%i : register(c%i);\n", i, CONST_VS_LIGHTSPOTCOEF + i); } WRITE(p, "float3 u_lightambient%i : register(c%i);\n", i, CONST_VS_LIGHTAMBIENT + i); WRITE(p, "float3 u_lightdiffuse%i : register(c%i);\n", i, CONST_VS_LIGHTDIFFUSE + i); @@ -487,8 +487,8 @@ void GenerateVertexShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage l case GE_LIGHTTYPE_SPOT: case GE_LIGHTTYPE_UNKNOWN: WRITE(p, " float angle%i = dot(normalize(u_lightdir%i), toLight);\n", i, i); - WRITE(p, " if (angle%i >= u_lightangle%i) {\n", i, i); - WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, float3(1.0, distance, distance*distance)), 0.0, 1.0) * pow(angle%i, u_lightspotCoef%i);\n", i, i, i); + WRITE(p, " if (angle%i >= u_lightangle%i.x) {\n", i, i); + WRITE(p, " lightScale = clamp(1.0 / dot(u_lightatt%i, float3(1.0, distance, distance*distance)), 0.0, 1.0) * pow(angle%i, u_lightspotCoef%i.x);\n", i, i, i); WRITE(p, " } else {\n"); WRITE(p, " lightScale = 0.0;\n"); WRITE(p, " }\n"); From cef8dc907dd940a362f1739f64b840141bb266ce Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 13 Feb 2017 02:12:49 +0100 Subject: [PATCH 33/40] Last one for today --- GPU/D3D11/FramebufferManagerD3D11.h | 5 +++++ GPU/D3D11/TextureCacheD3D11.cpp | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 409e2157d2..bb0b5c84fb 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -82,6 +82,11 @@ public: virtual void RebindFramebuffer() override; + // TODO: Remove + ID3D11Buffer *GetDynamicQuadBuffer() { + return quadBuffer_; + } + protected: void DisableState() override; void ClearBuffer(bool keepState = false) override; diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index 864660cc7e..ae8792a58e 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -426,7 +426,7 @@ public: UV uv; }; - TextureShaderApplierD3D11(ID3D11DeviceContext *context, ID3D11PixelShader *pshader, float bufferW, float bufferH, int renderW, int renderH, float xoff, float yoff) + TextureShaderApplierD3D11(ID3D11DeviceContext *context, ID3D11PixelShader *pshader, ID3D11Buffer *dynamicBuffer, float bufferW, float bufferH, int renderW, int renderH, float xoff, float yoff) : context_(context), pshader_(pshader), bufferW_(bufferW), bufferH_(bufferH), renderW_(renderW), renderH_(renderH) { static const Pos pos[4] = { { -1, 1, 0 }, @@ -447,6 +447,11 @@ public: verts_[i].pos.y += yoff; verts_[i].uv = uv[i]; } + D3D11_MAPPED_SUBRESOURCE map; + context->Map(dynamicBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, &verts_[0], 4 * 5 * sizeof(float)); + context->Unmap(dynamicBuffer, 0); + vbuffer_ = dynamicBuffer; } void ApplyBounds(const KnownVertexBounds &bounds, u32 uoff, u32 voff, float xoff, float yoff) { @@ -533,7 +538,7 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra float xoff = -0.5f / framebuffer->renderWidth; float yoff = 0.5f / framebuffer->renderHeight; - TextureShaderApplierD3D11 shaderApply(context_, pshader, framebuffer->bufferWidth, framebuffer->bufferHeight, framebuffer->renderWidth, framebuffer->renderHeight, xoff, yoff); + TextureShaderApplierD3D11 shaderApply(context_, pshader, framebufferManagerD3D11_->GetDynamicQuadBuffer(), framebuffer->bufferWidth, framebuffer->bufferHeight, framebuffer->renderWidth, framebuffer->renderHeight, xoff, yoff); shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset, xoff, yoff); shaderApply.Use(depalShaderCache_->GetDepalettizeVertexShader(), depalShaderCache_->GetInputLayout()); From 780006489eda49c0d369495093c41d6d2c1add7c Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 13 Feb 2017 17:29:36 +0100 Subject: [PATCH 34/40] D3D11 Attempt at fixing Star Ocean stencil .. doesn't quite work. --- GPU/D3D11/FramebufferManagerD3D11.cpp | 2 + GPU/D3D11/FramebufferManagerD3D11.h | 1 + GPU/D3D11/StencilBufferD3D11.cpp | 89 ++++++++++++++++----------- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 7d336f2e99..12ada5fb7e 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -139,6 +139,8 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() { stencilUploadVS_->Release(); if (stencilUploadInputLayout_) stencilUploadInputLayout_->Release(); + if (stencilValueBuffer_) + stencilValueBuffer_->Release(); } void FramebufferManagerD3D11::SetTextureCache(TextureCacheD3D11 *tc) { diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index bb0b5c84fb..2eaba71829 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -131,6 +131,7 @@ private: ID3D11PixelShader *stencilUploadPS_ = nullptr; ID3D11VertexShader *stencilUploadVS_ = nullptr; ID3D11InputLayout *stencilUploadInputLayout_ = nullptr; + ID3D11Buffer *stencilValueBuffer_ = nullptr; ID3D11DepthStencilState *stencilMaskStates_[256]{}; TextureCacheD3D11 *textureCacheD3D11_; diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp index 2c8878f2a8..03ab4437e7 100644 --- a/GPU/D3D11/StencilBufferD3D11.cpp +++ b/GPU/D3D11/StencilBufferD3D11.cpp @@ -31,42 +31,46 @@ #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) -struct StencilUB { - float u_stencilValue[4]; +struct StencilValueUB { + uint32_t u_stencilValue[4]; }; -static const char *stencil_ps = -"SamplerState samp : register(s0);\n" -"Texture2D tex : register(t0);\n" -"cbuffer base : register(b0) {\n" -" float4 u_stencilValue;\n" -"};\n" -"struct PS_IN {\n" -" float2 v_texcoord0 : TEXCOORD0;\n" -"};\n" -"float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n" -"float4 main(PS_IN In) : SV_Target {\n" -" float4 index = tex.Sample(samp, In.v_texcoord0);\n" -" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue.x);\n" -" clip(fmod(floor(shifted), 2.0) - 0.99);\n" -" return index.aaaa;\n" -"}\n"; +static const char *stencil_ps = R"( +SamplerState samp : register(s0); +Texture2D tex : register(t0); +cbuffer base : register(b0) { + uint4 u_stencilValue; +}; +struct PS_IN { + float2 v_texcoord0 : TEXCOORD0; +}; +float4 main(PS_IN In) : SV_Target { + float4 index = tex.Sample(samp, In.v_texcoord0); + uint indexBits = uint(index.a * 256.0); + if ((indexBits & u_stencilValue.x) == 0) + discard; + return index.aaaa; +} +)"; -static const char *stencil_vs = -"struct VS_IN {\n" -" float4 a_position : POSITION;\n" -" float2 a_texcoord0 : TEXCOORD0;\n" -"};\n" -"struct VS_OUT {\n" -" float2 v_texcoord0 : TEXCOORD0;\n" -" float4 position : SV_Position;\n" -"};\n" -"VS_OUT main(VS_IN In) {\n" -" VS_OUT Out;\n" -" Out.position = In.a_position;\n" -" Out.v_texcoord0 = In.a_texcoord0;\n" -" return Out;\n" -"}\n"; +// static const char *stencil_ps_fast; + +static const char *stencil_vs = R"( +struct VS_IN { + float4 a_position : POSITION; + float2 a_texcoord0 : TEXCOORD0; +}; +struct VS_OUT { + float2 v_texcoord0 : TEXCOORD0; + float4 position : SV_Position; +}; +VS_OUT main(VS_IN In) { + VS_OUT Out; + Out.position = In.a_position; + Out.v_texcoord0 = In.a_texcoord0; + return Out; +} +)"; static u8 StencilBits5551(const u8 *ptr8, u32 numPixels) { const u32 *ptr = (const u32 *)ptr8; @@ -174,6 +178,14 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ stencilUploadVS_ = CreateVertexShaderD3D11(device_, stencil_vs, strlen(stencil_vs), &byteCode); device_->CreateInputLayout(g_QuadVertexElements, 2, byteCode.data(), byteCode.size(), &stencilUploadInputLayout_); } + if (!stencilValueBuffer_) { + D3D11_BUFFER_DESC desc{}; + desc.ByteWidth = sizeof(StencilValueUB); + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + device_->CreateBuffer(&desc, nullptr, &stencilValueBuffer_); + } shaderManager_->DirtyLastShader(); @@ -197,8 +209,8 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ float coord[20] = { 0.0f,0.0f,0.0f, 0.0f,0.0f, fw,0.0f,0.0f, 1.0f,0.0f, - fw,fh,0.0f, 1.0f,1.0f, 0.0f,fh,0.0f, 0.0f,1.0f, + fw,fh,0.0f, 1.0f,1.0f, }; // I think all these calculations pretty much cancel out? float invDestW = 1.0f / (fw * 0.5f); @@ -258,7 +270,14 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ desc.BackFace = desc.FrontFace; device_->CreateDepthStencilState(&desc, &stencilMaskStates_[mask]); } - context_->OMSetDepthStencilState(stencilMaskStates_[mask], value); + context_->OMSetDepthStencilState(stencilMaskStates_[mask], 0xFF); + + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(stencilValueBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + StencilValueUB ub{ (uint32_t)value }; + memcpy(map.pData, &ub, sizeof(ub)); + context_->Unmap(stencilValueBuffer_, 0); + context_->PSSetConstantBuffers(0, 1, &stencilValueBuffer_); context_->Draw(4, 0); } RebindFramebuffer(); From 6d4d638746adbe9e9c7b727e88f40e604fc984c5 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 14 Feb 2017 01:31:45 +0100 Subject: [PATCH 35/40] D3D11: Fix some color issues by doing thing similarly to DX9. Can be optimized later. --- GPU/D3D11/FramebufferManagerD3D11.cpp | 6 +++--- GPU/D3D11/TextureCacheD3D11.cpp | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 12ada5fb7e..a03983f209 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -177,7 +177,7 @@ void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferForm desc.MipLevels = 1; desc.ArraySize = 1; desc.SampleDesc.Count = 1; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; device_->CreateTexture2D(&desc, nullptr, &drawPixelsTex_); device_->CreateShaderResourceView(drawPixelsTex_, nullptr, &drawPixelsTexView_); @@ -224,7 +224,7 @@ void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferForm { const u32_le *src = (const u32_le *)srcPixels + srcStride * y; u32 *dst = (u32 *)(convBuf + map.RowPitch * y); - memcpy(dst, src, width * 4); + ConvertRGBA8888ToBGRA8888(dst, src, width); } break; } @@ -233,7 +233,7 @@ void FramebufferManagerD3D11::MakePixelTexture(const u8 *srcPixels, GEBufferForm for (int y = 0; y < height; y++) { const u32_le *src = (const u32_le *)srcPixels + srcStride * y; u32 *dst = (u32 *)(convBuf + map.RowPitch * y); - memcpy(dst, src, width * 4); + ConvertRGBA8888ToBGRA8888(dst, src, width); } } diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index ae8792a58e..d1a8da24b7 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -226,10 +226,10 @@ DXGI_FORMAT getClutDestFormatD3D11(GEPaletteFormat format) { case GE_CMODE_16BIT_BGR5650: return DXGI_FORMAT_B5G6R5_UNORM; case GE_CMODE_32BIT_ABGR8888: - return DXGI_FORMAT_R8G8B8A8_UNORM; + return DXGI_FORMAT_B8G8R8A8_UNORM; } // Should never be here ! - return DXGI_FORMAT_R8G8B8A8_UNORM; + return DXGI_FORMAT_B8G8R8A8_UNORM; } void TextureCacheD3D11::UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key) { @@ -628,7 +628,7 @@ void TextureCacheD3D11::SetTexture(bool force) { TexCache::iterator iter = cache.find(cachekey); TexCacheEntry *entry = NULL; gstate_c.needShaderTexClamp = false; - gstate_c.bgraTexture = false; + gstate_c.bgraTexture = true; gstate_c.skipDrawReason &= ~SKIPDRAW_BAD_FB_TEXTURE; bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; @@ -1032,7 +1032,7 @@ DXGI_FORMAT TextureCacheD3D11::GetDestFormat(GETextureFormat format, GEPaletteFo case GE_TFMT_DXT3: case GE_TFMT_DXT5: default: - return DXGI_FORMAT_R8G8B8A8_UNORM; + return DXGI_FORMAT_B8G8R8A8_UNORM; } } @@ -1062,7 +1062,7 @@ ReplacedTextureFormat FromD3D11Format(u32 fmt) { case DXGI_FORMAT_B5G6R5_UNORM: return ReplacedTextureFormat::F_5650; case DXGI_FORMAT_B5G5R5A1_UNORM: return ReplacedTextureFormat::F_5551; case DXGI_FORMAT_B4G4R4A4_UNORM: return ReplacedTextureFormat::F_4444; - case DXGI_FORMAT_R8G8B8A8_UNORM: default: return ReplacedTextureFormat::F_8888; + case DXGI_FORMAT_B8G8R8A8_UNORM: default: return ReplacedTextureFormat::F_8888; } } @@ -1071,7 +1071,7 @@ DXGI_FORMAT ToDXGIFormat(ReplacedTextureFormat fmt) { case ReplacedTextureFormat::F_5650: return DXGI_FORMAT_B5G6R5_UNORM; case ReplacedTextureFormat::F_5551: return DXGI_FORMAT_B5G5R5A1_UNORM; case ReplacedTextureFormat::F_4444: return DXGI_FORMAT_B4G4R4A4_UNORM; - case ReplacedTextureFormat::F_8888: default: return DXGI_FORMAT_R8G8B8A8_UNORM; + case ReplacedTextureFormat::F_8888: default: return DXGI_FORMAT_B8G8R8A8_UNORM; } } @@ -1091,7 +1091,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & tw *= scaleFactor; th *= scaleFactor; if (scaleFactor > 1) { - tfmt = DXGI_FORMAT_R8G8B8A8_UNORM; + tfmt = DXGI_FORMAT_B8G8R8A8_UNORM; } } @@ -1134,7 +1134,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & GEPaletteFormat clutformat = gstate.getClutPaletteFormat(); u32 texaddr = gstate.getTextureAddress(level); int bufw = GetTextureBufw(level, texaddr, tfmt); - int bpp = dstFmt == DXGI_FORMAT_R8G8B8A8_UNORM ? 4 : 2; + int bpp = dstFmt == DXGI_FORMAT_B8G8R8A8_UNORM ? 4 : 2; mapRowPitch = std::max(bufw, w) * 4; mapData = new u32[mapRowPitch / 4 * h]{}; @@ -1147,7 +1147,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & decPitch = w * bpp; } - bool decSuccess = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, true, false); + bool decSuccess = DecodeTextureLevel((u8 *)pixelData, decPitch, tfmt, clutformat, texaddr, level, bufw, false, false); if (!decSuccess) { memset(pixelData, 0, decPitch * h); } @@ -1157,7 +1157,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture & pixelData = (u32 *)mapData; // We always end up at 8888. Other parts assume this. - assert(dstFmt == DXGI_FORMAT_R8G8B8A8_UNORM); + assert(dstFmt == DXGI_FORMAT_B8G8R8A8_UNORM); bpp = sizeof(u32); decPitch = w * bpp; From b51bcd2247fe170e9d6523a7c667dd50e2e3ab81 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 14 Feb 2017 01:54:00 +0100 Subject: [PATCH 36/40] D3D11 Stencil ref fix, fixes Star Ocean stencil-depth --- GPU/D3D11/StateMappingD3D11.cpp | 2 +- GPU/D3D11/StencilBufferD3D11.cpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index e1ad394a9e..90c448b477 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -422,5 +422,5 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { void DrawEngineD3D11::ApplyDrawStateLate(bool applyStencilRef, uint8_t stencilRef) { textureCache_->ApplyTexture(); - context_->OMSetDepthStencilState(depthStencilState_, applyStencilRef ? stencilRef : 0xFF); + context_->OMSetDepthStencilState(depthStencilState_, applyStencilRef ? stencilRef : dynState_.stencilRef); } \ No newline at end of file diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp index 03ab4437e7..b3064982e9 100644 --- a/GPU/D3D11/StencilBufferD3D11.cpp +++ b/GPU/D3D11/StencilBufferD3D11.cpp @@ -228,17 +228,15 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ shaderManager_->DirtyLastShader(); textureCacheD3D11_->ForgetLastTexture(); - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF); + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0], nullptr, 0xFFFFFFFF); context_->IASetInputLayout(stencilUploadInputLayout_); context_->PSSetShader(stencilUploadPS_, nullptr, 0); context_->VSSetShader(stencilUploadVS_, nullptr, 0); context_->PSSetShaderResources(0, 1, &drawPixelsTexView_); + context_->RSSetState(stockD3D11.rasterStateNoCull); context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context_->RSSetState(stockD3D11.rasterStateNoCull); context_->IASetVertexBuffers(0, 1, &quadBuffer_, &quadStride_, &quadOffset_); - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF); context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); - context_->RSSetState(stockD3D11.rasterStateNoCull); for (int i = 1; i < values; i += i) { if (!(usedBits & i)) { From b5034c4e00a02639633f5b8d505f098c02209bac Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 14 Feb 2017 10:33:42 +0100 Subject: [PATCH 37/40] Hide the D3D11 backend if Windows version is older than Win8 --- CMakeLists.txt | 2 + Common/Common.vcxproj | 4 +- Common/Common.vcxproj.filters | 4 +- Common/OSVersion.cpp | 87 +++++++++++++++++++++++++++++++++++ Common/OSVersion.h | 11 +++++ UI/GameSettingsScreen.cpp | 8 ++++ Windows/main.cpp | 82 +-------------------------------- 7 files changed, 116 insertions(+), 82 deletions(-) create mode 100644 Common/OSVersion.cpp create mode 100644 Common/OSVersion.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4776215820..b1921725f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -347,6 +347,8 @@ add_library(Common STATIC Common/Misc.cpp Common/MsgHandler.cpp Common/MsgHandler.h + Common/OSVersion.cpp + Common/OSVersion.h Common/StringUtils.cpp Common/StringUtils.h Common/ThreadPools.cpp diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index c2ed3cd411..c2266ce701 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -233,6 +233,7 @@ + @@ -300,6 +301,7 @@ + Create Create @@ -326,4 +328,4 @@ - + \ No newline at end of file diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index c707726aa0..874c86925a 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -73,6 +73,7 @@ Vulkan + @@ -135,6 +136,7 @@ + @@ -150,4 +152,4 @@ {c14d66ef-5f7c-4565-975a-72774e7ccfb9} - + \ No newline at end of file diff --git a/Common/OSVersion.cpp b/Common/OSVersion.cpp new file mode 100644 index 0000000000..4e1a2f5381 --- /dev/null +++ b/Common/OSVersion.cpp @@ -0,0 +1,87 @@ + +#ifdef _MSC_VER + +#include +#include "OSVersion.h" +#include "Common/CommonWindows.h" + +bool DoesVersionMatchWindows(uint32_t major, uint32_t minor, uint32_t spMajor, uint32_t spMinor) { + uint64_t conditionMask = 0; + OSVERSIONINFOEX osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = major; + osvi.dwMinorVersion = minor; + osvi.wServicePackMajor = spMajor; + osvi.wServicePackMinor = spMinor; + uint32_t op = VER_EQUAL; + + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, op); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, op); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMAJOR, op); + VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMINOR, op); + + const uint32_t typeMask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; + + return VerifyVersionInfo(&osvi, typeMask, conditionMask) != FALSE; +} + +std::string GetWindowsVersion() { + const bool IsWindowsXPSP2 = DoesVersionMatchWindows(5, 1, 2, 0); + const bool IsWindowsXPSP3 = DoesVersionMatchWindows(5, 1, 3, 0); + const bool IsWindowsVista = DoesVersionMatchWindows(6, 0); + const bool IsWindowsVistaSP1 = DoesVersionMatchWindows(6, 0, 1, 0); + const bool IsWindowsVistaSP2 = DoesVersionMatchWindows(6, 0, 2, 0); + const bool IsWindows7 = DoesVersionMatchWindows(6, 1); + const bool IsWindows7SP1 = DoesVersionMatchWindows(6, 1, 1, 0); + const bool IsWindows8 = DoesVersionMatchWindows(6, 2); + const bool IsWindows8_1 = DoesVersionMatchWindows(6, 3); + + if (IsWindowsXPSP2) + return "Microsoft Windows XP, Service Pack 2"; + + if (IsWindowsXPSP3) + return "Microsoft Windows XP, Service Pack 3"; + + if (IsWindowsVista) + return "Microsoft Windows Vista"; + + if (IsWindowsVistaSP1) + return "Microsoft Windows Vista, Service Pack 1"; + + if (IsWindowsVistaSP2) + return "Microsoft Windows Vista, Service Pack 2"; + + if (IsWindows7) + return "Microsoft Windows 7"; + + if (IsWindows7SP1) + return "Microsoft Windows 7, Service Pack 1"; + + if (IsWindows8) + return "Microsoft Windows 8 or greater"; // "Applications not manifested for Windows 10 will return the Windows 8 OS version value (6.2)." + + if (IsWindows8_1) + return "Microsoft Windows 8.1"; + + return "Unsupported version of Microsoft Windows."; +} + +std::string GetWindowsSystemArchitecture() { + SYSTEM_INFO sysinfo; + ZeroMemory(&sysinfo, sizeof(SYSTEM_INFO)); + GetNativeSystemInfo(&sysinfo); + + if (sysinfo.wProcessorArchitecture & PROCESSOR_ARCHITECTURE_AMD64) + return "(x64)"; + // Need to check for equality here, since ANDing with 0 is always 0. + else if (sysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) + return "(x86)"; + else if (sysinfo.wProcessorArchitecture & PROCESSOR_ARCHITECTURE_ARM) + return "(ARM)"; + else + return "(Unknown)"; +} + +#endif \ No newline at end of file diff --git a/Common/OSVersion.h b/Common/OSVersion.h new file mode 100644 index 0000000000..ded3801046 --- /dev/null +++ b/Common/OSVersion.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#ifdef _MSC_VER + +bool DoesVersionMatchWindows(uint32_t major, uint32_t minor, uint32_t spMajor = 0, uint32_t spMinor = 0); +std::string GetWindowsVersion(); +std::string GetWindowsSystemArchitecture(); + +#endif \ No newline at end of file diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 48c1d09dfb..a60ccdc04c 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -44,6 +44,7 @@ #include "Common/KeyMap.h" #include "Common/FileUtil.h" +#include "Common/OSVersion.h" #include "Core/Config.h" #include "Core/Host.h" #include "Core/System.h" @@ -159,6 +160,13 @@ void GameSettingsScreen::CreateViews() { #if !defined(_WIN32) renderingBackendChoice->HideChoice(1); // D3D9 renderingBackendChoice->HideChoice(2); // D3D11 +#else + if (!DoesVersionMatchWindows(6, 2)) { + // Hide the D3D11 choice if Windows version is older than Windows 8. + // We will later be able to support Windows 7 and Vista (unofficially) as well, + // but we currently depend on a texture format that's only available in Win8+. + renderingBackendChoice->HideChoice(2); // D3D11 + } #endif #if !defined(_WIN32) // TODO: Add dynamic runtime check for Vulkan support on Android diff --git a/Windows/main.cpp b/Windows/main.cpp index 3df8e75021..3b6a10a307 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -19,6 +19,8 @@ #include #include "Common/CommonWindows.h" +#include "Common/OSVersion.h" + #include #include #include @@ -85,86 +87,6 @@ void Vibrate(int length_ms) { // Ignore on PC } -bool DoesVersionMatchWindows(const u32 major, const u32 minor, const u32 spMajor = 0, const u32 spMinor = 0) { - u64 conditionMask = 0; - OSVERSIONINFOEX osvi; - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - - osvi.dwOSVersionInfoSize = sizeof(osvi); - osvi.dwMajorVersion = major; - osvi.dwMinorVersion = minor; - osvi.wServicePackMajor = spMajor; - osvi.wServicePackMinor = spMinor; - u32 op = VER_EQUAL; - - VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, op); - VER_SET_CONDITION(conditionMask, VER_MINORVERSION, op); - VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMAJOR, op); - VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMINOR, op); - - const u32 typeMask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; - - return VerifyVersionInfo(&osvi, typeMask, conditionMask) != FALSE; -} - -std::string GetWindowsVersion() { - const bool IsWindowsXPSP2 = DoesVersionMatchWindows(5, 1, 2, 0); - const bool IsWindowsXPSP3 = DoesVersionMatchWindows(5, 1, 3, 0); - const bool IsWindowsVista = DoesVersionMatchWindows(6, 0); - const bool IsWindowsVistaSP1 = DoesVersionMatchWindows(6, 0, 1, 0); - const bool IsWindowsVistaSP2 = DoesVersionMatchWindows(6, 0, 2, 0); - const bool IsWindows7 = DoesVersionMatchWindows(6, 1); - const bool IsWindows7SP1 = DoesVersionMatchWindows(6, 1, 1, 0); - const bool IsWindows8 = DoesVersionMatchWindows(6, 2); - const bool IsWindows8_1 = DoesVersionMatchWindows(6, 3); - - - if (IsWindowsXPSP2) - return "Microsoft Windows XP, Service Pack 2"; - - if (IsWindowsXPSP3) - return "Microsoft Windows XP, Service Pack 3"; - - if (IsWindowsVista) - return "Microsoft Windows Vista"; - - if (IsWindowsVistaSP1) - return "Microsoft Windows Vista, Service Pack 1"; - - if (IsWindowsVistaSP2) - return "Microsoft Windows Vista, Service Pack 2"; - - if (IsWindows7) - return "Microsoft Windows 7"; - - if (IsWindows7SP1) - return "Microsoft Windows 7, Service Pack 1"; - - if (IsWindows8) - return "Microsoft Windows 8 or greater"; // "Applications not manifested for Windows 10 will return the Windows 8 OS version value (6.2)." - - if (IsWindows8_1) - return "Microsoft Windows 8.1"; - - return "Unsupported version of Microsoft Windows."; -} - -std::string GetWindowsSystemArchitecture() { - SYSTEM_INFO sysinfo; - ZeroMemory(&sysinfo, sizeof(SYSTEM_INFO)); - GetNativeSystemInfo(&sysinfo); - - if (sysinfo.wProcessorArchitecture & PROCESSOR_ARCHITECTURE_AMD64) - return "(x64)"; - // Need to check for equality here, since ANDing with 0 is always 0. - else if (sysinfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) - return "(x86)"; - else if (sysinfo.wProcessorArchitecture & PROCESSOR_ARCHITECTURE_ARM) - return "(ARM)"; - else - return "(Unknown)"; -} - // Adapted mostly as-is from http://www.gamedev.net/topic/495075-how-to-retrieve-info-about-videocard/?view=findpost&p=4229170 // so credit goes to that post's author, and in turn, the author of the site mentioned in that post (which seems to be down?). std::string GetVideoCardDriverVersion() { From 56b3a823ba3b944807ba734aa5d31df2b334d67b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 14 Feb 2017 10:34:55 +0100 Subject: [PATCH 38/40] D3D11: Improved alpha/color test, like in GL/Vulkan --- GPU/Directx9/PixelShaderGeneratorDX9.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/GPU/Directx9/PixelShaderGeneratorDX9.cpp b/GPU/Directx9/PixelShaderGeneratorDX9.cpp index a59bb1f519..b392804c3b 100644 --- a/GPU/Directx9/PixelShaderGeneratorDX9.cpp +++ b/GPU/Directx9/PixelShaderGeneratorDX9.cpp @@ -112,14 +112,14 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage if (enableAlphaTest) { if (lang == HLSL_D3D11) { - WRITE(p, "uint roundAndScaleTo255f(float x) { return uint(floor(x * 255.0f + 0.5f)); }\n"); + WRITE(p, "uint roundAndScaleTo255i(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) { if (lang == HLSL_D3D11) { - WRITE(p, "uint3 roundAndScaleTo255v(float3 x) { return uint3(floor(x * 255.0f + 0.5f)); }\n"); + WRITE(p, "uint3 roundAndScaleTo255iv(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"); } @@ -278,10 +278,17 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage const char *alphaTestFuncs[] = { "#", "#", " != ", " == ", " >= ", " > ", " <= ", " < " }; // never/always don't make sense if (alphaTestFuncs[alphaTestFunc][0] != '#') { // TODO: Rewrite this to use clip() appropriately (like, clip(v.a - u_alphacolorref.a)) - WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) clip(-1);\n", alphaTestFuncs[alphaTestFunc]); + if (lang == HLSL_D3D11) { + WRITE(p, " if ((roundAndScaleTo255i(v.a) & u_alphacolormask.a) %s u_alphacolorref.a) discard;\n", alphaTestFuncs[alphaTestFunc]); + } else { + WRITE(p, " if (roundAndScaleTo255f(v.a) %s u_alphacolorref.a) clip(-1);\n", alphaTestFuncs[alphaTestFunc]); + } } else { // This means NEVER. See above. - WRITE(p, " clip(-1);\n"); + if (lang == HLSL_D3D11) + WRITE(p, " discard;\n"); + else + WRITE(p, " clip(-1);\n"); } } } @@ -303,8 +310,13 @@ bool GenerateFragmentShaderHLSL(const ShaderID &id, char *buffer, ShaderLanguage const char *colorTestFuncs[] = { "#", "#", " != ", " == " }; // never/always don't make sense if (colorTestFuncs[colorTestFunc][0] != '#') { 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); + if (lang == HLSL_D3D11) { + WRITE(p, " uint3 v_scaled = roundAndScaleTo255iv(v.rgb);\n"); + WRITE(p, " if ((v_scaled & u_alphacolormask.rgb) %s (u_alphacolorref.rgb & u_alphacolormask.rgb)) discard;\n", colorTestFuncs[colorTestFunc]); + } else { + 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 { WRITE(p, " clip(-1);\n"); From a9e267ae7af3b921ea914b7766e36aa0fda9b4d2 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 14 Feb 2017 10:36:58 +0100 Subject: [PATCH 39/40] Enable dualsource blend effects (glows on transparent things in Wipeout, for example) --- GPU/D3D11/GPU_D3D11.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 50c315b64b..2410a057e3 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -508,7 +508,7 @@ void GPU_D3D11::CheckGPUFeatures() { features |= GPU_SUPPORTS_ACCURATE_DEPTH; ///features |= GPU_SUPPORTS_ANISOTROPY; features |= GPU_SUPPORTS_OES_TEXTURE_NPOT; - //features |= GPU_SUPPORTS_DUALSOURCE_BLEND; + features |= GPU_SUPPORTS_DUALSOURCE_BLEND; // features |= GPU_SUPPORTS_ANY_COPY_IMAGE; From 77d087776c342cd04434f90c3e8e57d4ad86f4af Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 14 Feb 2017 11:21:53 +0100 Subject: [PATCH 40/40] D3D11: Support window resize --- Windows/GPU/D3D11Context.cpp | 19 +---- ext/native/thin3d/thin3d_d3d11.cpp | 122 +++++++++++++++++------------ 2 files changed, 76 insertions(+), 65 deletions(-) diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index cdd773dbe6..d4a9286193 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -84,33 +84,18 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { #endif draw_ = Draw::T3DCreateD3D11Context(device_, context_, hWnd_); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER); return true; } void D3D11Context::Resize() { draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER); draw_->HandleEvent(Draw::Event::RESIZED); - // This should only be called from the emu thread. - /* - int xres, yres; - GetRes(hWnd, xres, yres); - bool w_changed = pp.BackBufferWidth != xres; - bool h_changed = pp.BackBufferHeight != yres; - - if (device_ && (w_changed || h_changed)) { - pp.BackBufferWidth = xres; - pp.BackBufferHeight = yres; - HRESULT hr = device_->Reset(&pp); - if (FAILED(hr)) { - ERROR_LOG_REPORT(G3D, "Unable to reset D3D device"); - PanicAlert("Unable to reset D3D11 device"); - } - } - */ draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER); } void D3D11Context::Shutdown() { + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER); delete draw_; draw_ = nullptr; context_->ClearState(); diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 50b8053d21..ab89fb0854 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -109,13 +109,7 @@ public: } } - void HandleEvent(Event ev) override { - switch (ev) { - case Event::PRESENT_REQUESTED: - swapChain_->Present(0, 0); - break; - } - } + void HandleEvent(Event ev) override; private: void ApplyCurrentState(); @@ -213,47 +207,6 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *co dxgiFactory->MakeWindowAssociation(hWnd_, DXGI_MWA_NO_ALT_ENTER); dxgiFactory->Release(); - if (FAILED(hr)) - return; - - // Create a render target view - ID3D11Texture2D* pBackBuffer = nullptr; - hr = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&pBackBuffer)); - if (FAILED(hr)) - return; - - hr = device_->CreateRenderTargetView(pBackBuffer, nullptr, &bbRenderTargetView_); - pBackBuffer->Release(); - if (FAILED(hr)) - return; - - // Create depth stencil texture - D3D11_TEXTURE2D_DESC descDepth{}; - descDepth.Width = width; - descDepth.Height = height; - descDepth.MipLevels = 1; - descDepth.ArraySize = 1; - descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; - descDepth.SampleDesc.Count = 1; - descDepth.SampleDesc.Quality = 0; - descDepth.Usage = D3D11_USAGE_DEFAULT; - descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; - descDepth.CPUAccessFlags = 0; - descDepth.MiscFlags = 0; - hr = device_->CreateTexture2D(&descDepth, nullptr, &bbDepthStencilTex_); - - // Create the depth stencil view - D3D11_DEPTH_STENCIL_VIEW_DESC descDSV{}; - descDSV.Format = descDepth.Format; - descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - descDSV.Texture2D.MipSlice = 0; - hr = device_->CreateDepthStencilView(bbDepthStencilTex_, &descDSV, &bbDepthStencilView_); - - context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_); - - curRenderTargetView_ = bbRenderTargetView_; - curDepthStencilView_ = bbDepthStencilView_; - CreatePresets(); } @@ -261,6 +214,79 @@ D3D11DrawContext::~D3D11DrawContext() { } +void D3D11DrawContext::HandleEvent(Event ev) { + switch (ev) { + case Event::PRESENT_REQUESTED: + swapChain_->Present(0, 0); + break; + case Event::RESIZED: { + int width; + int height; + GetRes(hWnd_, width, height); + swapChain_->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0); + break; + } + case Event::LOST_BACKBUFFER: { + if (curRenderTargetView_ == bbRenderTargetView_ || curDepthStencilView_ == bbDepthStencilView_) { + ID3D11RenderTargetView *view = nullptr; + context_->OMSetRenderTargets(1, &view, nullptr); + curRenderTargetView_ = nullptr; + curDepthStencilView_ = nullptr; + } + bbRenderTargetView_->Release(); + bbRenderTargetView_ = nullptr; + bbDepthStencilView_->Release(); + bbDepthStencilView_ = nullptr; + bbDepthStencilTex_->Release(); + bbDepthStencilTex_ = nullptr; + break; + } + case Event::GOT_BACKBUFFER: { + int width; + int height; + GetRes(hWnd_, width, height); + // Create a render target view + ID3D11Texture2D* pBackBuffer = nullptr; + HRESULT hr = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&pBackBuffer)); + if (FAILED(hr)) + return; + + hr = device_->CreateRenderTargetView(pBackBuffer, nullptr, &bbRenderTargetView_); + pBackBuffer->Release(); + if (FAILED(hr)) + return; + + // Create depth stencil texture + D3D11_TEXTURE2D_DESC descDepth{}; + descDepth.Width = width; + descDepth.Height = height; + descDepth.MipLevels = 1; + descDepth.ArraySize = 1; + descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + descDepth.SampleDesc.Count = 1; + descDepth.SampleDesc.Quality = 0; + descDepth.Usage = D3D11_USAGE_DEFAULT; + descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; + descDepth.CPUAccessFlags = 0; + descDepth.MiscFlags = 0; + hr = device_->CreateTexture2D(&descDepth, nullptr, &bbDepthStencilTex_); + + // Create the depth stencil view + D3D11_DEPTH_STENCIL_VIEW_DESC descDSV{}; + descDSV.Format = descDepth.Format; + descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + descDSV.Texture2D.MipSlice = 0; + hr = device_->CreateDepthStencilView(bbDepthStencilTex_, &descDSV, &bbDepthStencilView_); + + context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_); + + curRenderTargetView_ = bbRenderTargetView_; + curDepthStencilView_ = bbDepthStencilView_; + break; + } + } +} + void D3D11DrawContext::SetViewports(int count, Viewport *viewports) { D3D11_VIEWPORT vp[4]; for (int i = 0; i < count; i++) {