#pragma once #include "d3d9_caps.h" #include "d3d9_constant_set.h" #include "../dxso/dxso_common.h" #include "../util/util_matrix.h" #include "d3d9_surface.h" #include "d3d9_shader.h" #include "d3d9_vertex_declaration.h" #include "d3d9_buffer.h" #include #include #include namespace dxvk { static constexpr uint32_t RenderStateCount = 256; static constexpr uint32_t SamplerStateCount = D3DSAMP_DMAPOFFSET + 1; static constexpr uint32_t SamplerCount = 21; static constexpr uint32_t TextureStageStateCount = DXVK_TSS_COUNT; namespace hacks::PointSize { static constexpr DWORD AlphaToCoverageDisabled = MAKEFOURCC('A', '2', 'M', '0'); static constexpr DWORD AlphaToCoverageEnabled = MAKEFOURCC('A', '2', 'M', '1'); } struct D3D9ClipPlane { float coeff[4]; }; struct D3D9RenderStateInfo { std::array fogColor = { }; float fogScale = 0.0f; float fogEnd = 1.0f; float fogDensity = 1.0f; float alphaRef = 0.0f; float pointSize = 1.0f; float pointSizeMin = 1.0f; float pointSizeMax = 64.0f; float pointScaleA = 1.0f; float pointScaleB = 0.0f; float pointScaleC = 0.0f; }; enum class D3D9RenderStateItem { FogColor = 0, FogScale = 1, FogEnd, FogDensity, AlphaRef, PointSize, PointSizeMin, PointSizeMax, PointScaleA, PointScaleB, PointScaleC, Count }; // This is needed in fixed function for POSITION_T support. // These are constants we need to * and add to move // Window Coords -> Real Coords w/ respect to the viewport. struct D3D9ViewportInfo { Vector4 inverseOffset; Vector4 inverseExtent; }; struct D3D9Light { D3D9Light(const D3DLIGHT9& light, Matrix4 viewMtx) { Diffuse = Vector4(light.Diffuse.r, light.Diffuse.g, light.Diffuse.b, light.Diffuse.a); Specular = Vector4(light.Specular.r, light.Specular.g, light.Specular.b, light.Specular.a); Ambient = Vector4(light.Ambient.r, light.Ambient.g, light.Ambient.b, light.Ambient.a); Position = viewMtx * Vector4(light.Position.x, light.Position.y, light.Position.z, 1.0f); Direction = Vector4(light.Direction.x, light.Direction.y, light.Direction.z, 0.0f); Direction = normalize(viewMtx * Direction); Type = light.Type; Range = light.Range; Falloff = light.Falloff; Attenuation0 = light.Attenuation0; Attenuation1 = light.Attenuation1; Attenuation2 = light.Attenuation2; Theta = cosf(light.Theta / 2.0f); Phi = cosf(light.Phi / 2.0f); } Vector4 Diffuse; Vector4 Specular; Vector4 Ambient; Vector4 Position; Vector4 Direction; D3DLIGHTTYPE Type; float Range; float Falloff; float Attenuation0; float Attenuation1; float Attenuation2; float Theta; float Phi; }; struct D3D9FixedFunctionVS { Matrix4 WorldView; Matrix4 NormalMatrix; Matrix4 InverseView; Matrix4 Projection; std::array TexcoordMatrices; D3D9ViewportInfo ViewportInfo; Vector4 GlobalAmbient; std::array Lights; D3DMATERIAL9 Material; float TweenFactor; }; struct D3D9FixedFunctionVertexBlendDataHW { Matrix4 WorldView[8]; }; struct D3D9FixedFunctionVertexBlendDataSW { Matrix4 WorldView[256]; }; struct D3D9FixedFunctionPS { Vector4 textureFactor; }; enum D3D9SharedPSStages { D3D9SharedPSStages_Constant, D3D9SharedPSStages_BumpEnvMat0, D3D9SharedPSStages_BumpEnvMat1, D3D9SharedPSStages_BumpEnvLScale, D3D9SharedPSStages_BumpEnvLOffset, D3D9SharedPSStages_Count, }; struct D3D9SharedPS { struct Stage { float Constant[4]; float BumpEnvMat[2][2]; float BumpEnvLScale; float BumpEnvLOffset; float Padding[2]; } Stages[8]; }; struct D3D9VBO { Com vertexBuffer; UINT offset = 0; UINT stride = 0; }; constexpr D3DLIGHT9 DefaultLight = { D3DLIGHT_DIRECTIONAL, // Type {1.0f, 1.0f, 1.0f, 1.0f}, // Diffuse {0.0f, 0.0f, 0.0f, 0.0f}, // Specular {0.0f, 0.0f, 0.0f, 0.0f}, // Ambient {0.0f, 0.0f, 0.0f}, // Position {0.0f, 0.0f, 0.0f}, // Direction 0.0f, // Range 0.0f, // Falloff 0.0f, 0.0f, 0.0f, // Attenuations [constant, linear, quadratic] 0.0f, // Theta 0.0f // Phi }; struct D3D9CapturableState { D3D9CapturableState(); ~D3D9CapturableState(); Com vertexDecl; Com indices; std::array renderStates = { 0 }; std::array< std::array, SamplerCount> samplerStates; std::array vertexBuffers; std::array< IDirect3DBaseTexture9*, SamplerCount> textures; Com vertexShader; Com pixelShader; D3DVIEWPORT9 viewport; RECT scissorRect; std::array< D3D9ClipPlane, caps::MaxClipPlanes> clipPlanes; std::array< std::array, caps::TextureStageCount> textureStages; D3D9ShaderConstantsVSSoftware vsConsts; D3D9ShaderConstantsPS psConsts; std::array streamFreq; std::array transforms; D3DMATERIAL9 material = D3DMATERIAL9(); std::vector> lights; std::array enabledLightIndices; bool IsLightEnabled(DWORD Index) { const auto& indices = enabledLightIndices; return std::find(indices.begin(), indices.end(), Index) != indices.end(); } }; template < DxsoProgramType ProgramType, D3D9ConstantType ConstantType, typename T> HRESULT UpdateStateConstants( D3D9CapturableState* pState, UINT StartRegister, const T* pConstantData, UINT Count, bool FloatEmu) { auto UpdateHelper = [&] (auto& set) { if constexpr (ConstantType == D3D9ConstantType::Float) { auto begin = reinterpret_cast(pConstantData); auto end = begin + Count; if (!FloatEmu) std::copy(begin, end, &set.fConsts[StartRegister]); else std::transform(begin, end, &set.fConsts[StartRegister], replaceNaN); } else if constexpr (ConstantType == D3D9ConstantType::Int) { auto begin = reinterpret_cast(pConstantData); auto end = begin + Count; std::copy(begin, end, &set.iConsts[StartRegister]); } else { for (uint32_t i = 0; i < Count; i++) { const uint32_t constantIdx = StartRegister + i; const uint32_t arrayIdx = constantIdx / 32; const uint32_t bitIdx = constantIdx % 32; const uint32_t bit = 1u << bitIdx; set.bConsts[arrayIdx] &= ~bit; if (pConstantData[i]) set.bConsts[arrayIdx] |= bit; } } return D3D_OK; }; return ProgramType == DxsoProgramTypes::VertexShader ? UpdateHelper(pState->vsConsts) : UpdateHelper(pState->psConsts); } struct Direct3DState9 : public D3D9CapturableState { std::array, caps::MaxSimultaneousRenderTargets> renderTargets; Com depthStencil; }; struct D3D9InputAssemblyState { D3DPRIMITIVETYPE primitiveType = D3DPRIMITIVETYPE(0); uint32_t streamsInstanced = 0; uint32_t streamsUsed = 0; }; }