mirror of
https://github.com/rrika/cdcEngineDXHR.git
synced 2024-11-27 07:20:22 +00:00
944 lines
28 KiB
C++
944 lines
28 KiB
C++
#define NOMINMAX
|
|
#include <d3d11_1.h>
|
|
#include <cfloat>
|
|
#include <algorithm>
|
|
#include "cdcSys/Assert.h"
|
|
#include "buffers/PCDX11ConstantBuffer.h"
|
|
#include "buffers/PCDX11IndexBuffer.h"
|
|
#include "buffers/PCDX11UberConstantBuffer.h"
|
|
#include "buffers/PCDX11VertexBuffer.h"
|
|
#include "PCDX11StateManager.h"
|
|
#include "PCDX11StreamDecl.h"
|
|
#include "shaders/PCDX11ComputeShader.h"
|
|
#include "shaders/PCDX11PixelShader.h"
|
|
#include "shaders/PCDX11VertexShader.h"
|
|
#include "surfaces/PCDX11BaseTexture.h"
|
|
#include "surfaces/PCDX11DepthBuffer.h"
|
|
#include "surfaces/PCDX11RenderTarget.h"
|
|
|
|
bool operator==(D3D11_RASTERIZER_DESC const& a, D3D11_RASTERIZER_DESC const& b) {
|
|
return
|
|
a.FillMode == b.FillMode &&
|
|
a.CullMode == b.CullMode &&
|
|
a.FrontCounterClockwise == b.FrontCounterClockwise &&
|
|
a.DepthBias == b.DepthBias &&
|
|
a.DepthBiasClamp == b.DepthBiasClamp &&
|
|
a.SlopeScaledDepthBias == b.SlopeScaledDepthBias &&
|
|
a.DepthClipEnable == b.DepthClipEnable &&
|
|
a.ScissorEnable == b.ScissorEnable &&
|
|
a.MultisampleEnable == b.MultisampleEnable &&
|
|
a.AntialiasedLineEnable == b.AntialiasedLineEnable;
|
|
}
|
|
|
|
bool operator==(D3D11_DEPTH_STENCILOP_DESC const& a, D3D11_DEPTH_STENCILOP_DESC const& b) {
|
|
return
|
|
a.StencilFailOp == b.StencilFailOp &&
|
|
a.StencilDepthFailOp == b.StencilDepthFailOp &&
|
|
a.StencilPassOp == b.StencilPassOp &&
|
|
a.StencilFunc == b.StencilFunc;
|
|
}
|
|
|
|
bool operator==(D3D11_DEPTH_STENCIL_DESC const& a, D3D11_DEPTH_STENCIL_DESC const& b) {
|
|
return
|
|
a.DepthEnable == b.DepthEnable &&
|
|
a.DepthWriteMask == b.DepthWriteMask &&
|
|
a.DepthFunc == b.DepthFunc &&
|
|
a.StencilEnable == b.StencilEnable &&
|
|
a.StencilReadMask == b.StencilReadMask &&
|
|
a.StencilWriteMask == b.StencilWriteMask &&
|
|
a.FrontFace == b.FrontFace &&
|
|
a.BackFace == b.BackFace;
|
|
}
|
|
|
|
namespace cdc {
|
|
|
|
PCDX11StateManager::PCDX11StateManager() {}
|
|
|
|
PCDX11StateManager::PCDX11StateManager(ID3D11DeviceContext *deviceContext, ID3D11Device *device) :
|
|
m_deviceContext(deviceContext),
|
|
m_device(device),
|
|
m_indexBufferD3D(nullptr),
|
|
m_pixelShader(nullptr),
|
|
m_dirtySamplersFirst(20),
|
|
m_dirtySamplersLast(0),
|
|
m_dirtyShaderResourcesFirst(20),
|
|
m_dirtyShaderResourcesLast(0)
|
|
{
|
|
m_constantBufferVs[0] = nullptr;
|
|
m_uberConstantBuffer[0] = new PCDX11UberConstantBuffer(12);
|
|
m_uberConstantBuffer[1] = new PCDX11UberConstantBuffer(57);
|
|
m_uberConstantBuffer[2] = new PCDX11UberConstantBuffer(4);
|
|
m_uberConstantBuffer[3] = new PCDX11UberConstantBuffer(168);
|
|
m_uberConstantBuffer[4] = new PCDX11UberConstantBuffer(8);
|
|
m_uberConstantBuffer[5] = new PCDX11UberConstantBuffer(7);
|
|
m_uberConstantBuffer[6] = new PCDX11UberConstantBuffer(1);
|
|
|
|
memset(m_samplers, 0, 20 * 4);
|
|
memset(m_textures, 0, 20 * 4);
|
|
memset(m_textureViews, 0, 20 * 4);
|
|
memset(m_textureResources, 0, 20 * 4);
|
|
|
|
m_stencilParams.m_frontParams = 0xFF00000E;
|
|
m_stencilParams.m_backParams = 0xFF00000E;
|
|
m_stencilParams.m_writeMasks = 0;
|
|
m_stencilParams.m_hiStencil = 0xFFFF;
|
|
m_blendState = 0;
|
|
m_cullMode = ~0u;
|
|
|
|
m_projectMatrix = identity4x4;
|
|
m_viewMatrix = identity4x4;
|
|
m_viewProjectMatrix = identity4x4;
|
|
m_worldMatrix = identity4x4;
|
|
m_projectMatrixPtr = nullptr;
|
|
}
|
|
|
|
|
|
void PCDX11StateManager::reset() {
|
|
for (uint32_t i=0; i<20; i++) {
|
|
m_samplers[i] = nullptr;
|
|
m_textureViews[i] = nullptr;
|
|
m_textures[i] = nullptr;
|
|
m_textureResources[i] = nullptr;
|
|
m_samplerFilter[i] = 0;
|
|
m_samplerRepeat[i] = 0;
|
|
}
|
|
|
|
// TODO
|
|
|
|
m_dirtyShaderResourcesFirst = 0;
|
|
m_dirtySamplersFirst = 0;
|
|
|
|
m_renderTarget = nullptr;
|
|
m_depthBuffer = nullptr;
|
|
m_renderTargetStackIndex = 0;
|
|
|
|
m_dirtyRasterizerState = true;
|
|
m_dirtyDepthStencilState = true;
|
|
m_dirtyBlendState = true;
|
|
m_dirtyConstantBuffers = true;
|
|
m_dirtyShaderResources = true;
|
|
m_dirtySamplers = true;
|
|
|
|
m_topology = 0;
|
|
m_vertexStride = 0;
|
|
m_streamDecl = nullptr;
|
|
m_indexBufferD3D = nullptr;
|
|
m_vertexBufferD3D = nullptr;
|
|
m_pixelShader = nullptr;
|
|
m_vertexShader = nullptr;
|
|
|
|
// TODO
|
|
|
|
for (int i=0; i<7; i++)
|
|
m_constantBufferPs[i] = nullptr;
|
|
for (int i=0; i<7; i++)
|
|
m_constantBufferVs[i] = nullptr;
|
|
|
|
// TODO
|
|
|
|
m_alphaThreshold = 1.0f;
|
|
m_materialOpacity = 0.0f;
|
|
|
|
m_fogColor[0] = 0.0f;
|
|
m_fogColor[1] = 0.0f;
|
|
m_fogColor[2] = 0.0f;
|
|
m_fogColor[3] = 0.0f;
|
|
|
|
m_blendState = 0;
|
|
m_cullMode = ~0u;
|
|
|
|
// TODO
|
|
}
|
|
|
|
void PCDX11StateManager::setIndexBuffer(PCDX11IndexBuffer *indexBuffer) {
|
|
ID3D11Buffer *buffer = nullptr;
|
|
if (indexBuffer)
|
|
buffer = indexBuffer->getD3DBuffer();
|
|
|
|
if (buffer != m_indexBufferD3D) {
|
|
indexBuffer->method_10();
|
|
m_deviceContext->IASetIndexBuffer(buffer, DXGI_FORMAT_R16_UINT, 0);
|
|
m_indexBufferD3D = buffer;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setVertexBuffer(PCDX11VertexBuffer *vertexBuffer) {
|
|
if (vertexBuffer == nullptr)
|
|
return;
|
|
|
|
ID3D11Buffer *buffer = vertexBuffer->getD3DBuffer();
|
|
uint32_t stride = vertexBuffer->getStride();
|
|
uint32_t offset = 0;
|
|
if (buffer != m_vertexBufferD3D || stride != m_vertexStride) {
|
|
vertexBuffer->method14();
|
|
m_deviceContext->IASetVertexBuffers(0, 1, &buffer, &stride, &offset);
|
|
m_vertexBufferD3D = buffer;
|
|
m_vertexStride = stride;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setStreamDecl(PCDX11StreamDecl *streamDecl) {
|
|
if (streamDecl != m_streamDecl) {
|
|
if (!streamDecl->inputLayout) streamDecl->internalCreate(); // hack
|
|
streamDecl->apply();
|
|
m_streamDecl = streamDecl;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setPixelShader(PCDX11PixelShader *pixelShader) {
|
|
if (pixelShader != m_pixelShader) {
|
|
if (pixelShader) {
|
|
if (!pixelShader->m_requested)
|
|
pixelShader->requestShader();
|
|
if (pixelShader->m_keepWaiting)
|
|
pixelShader->awaitResource();
|
|
m_deviceContext->PSSetShader(pixelShader->m_d3dShader, nullptr, 0);
|
|
} else {
|
|
m_deviceContext->PSSetShader(nullptr, nullptr, 0);
|
|
}
|
|
m_pixelShader = pixelShader;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setVertexShader(PCDX11VertexShader *vertexShader) {
|
|
if (vertexShader != m_vertexShader) {
|
|
if (vertexShader) {
|
|
if (!vertexShader->m_requested)
|
|
vertexShader->requestShader();
|
|
if (vertexShader->m_keepWaiting)
|
|
vertexShader->awaitResource();
|
|
m_deviceContext->VSSetShader(vertexShader->m_d3dShader, nullptr, 0);
|
|
} else {
|
|
m_deviceContext->VSSetShader(nullptr, nullptr, 0);
|
|
}
|
|
m_vertexShader = vertexShader;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setPrimitiveTopology(int topology) {
|
|
// TODO: tesselation stuff
|
|
if (topology != m_topology) {
|
|
m_topology = topology;
|
|
m_deviceContext->IASetPrimitiveTopology((D3D11_PRIMITIVE_TOPOLOGY)topology);
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setDepthLayer(bool layer) {
|
|
// TODO
|
|
}
|
|
|
|
void PCDX11StateManager::setCullMode(CullMode cullMode, bool frontIsCounterClockwise) {
|
|
uint32_t compactCullMode = 2 * uint32_t(cullMode) + uint32_t(frontIsCounterClockwise);
|
|
if (compactCullMode != m_cullMode) {
|
|
m_cullMode = compactCullMode;
|
|
m_rasterizerDesc.CullMode =
|
|
cullMode == CullMode::back /*1*/ ? D3D11_CULL_BACK /*3*/ :
|
|
cullMode == CullMode::front /*2*/ ? D3D11_CULL_FRONT /*2*/ :
|
|
D3D11_CULL_NONE /*0*/;
|
|
m_rasterizerDesc.FrontCounterClockwise = frontIsCounterClockwise;
|
|
m_dirtyRasterizerState = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setDepthState(D3D11_COMPARISON_FUNC comparisonFunc, bool depthWrites) {
|
|
// untested
|
|
D3D11_DEPTH_WRITE_MASK depthWriteMask = depthWrites
|
|
? D3D11_DEPTH_WRITE_MASK_ALL
|
|
: D3D11_DEPTH_WRITE_MASK_ZERO;
|
|
|
|
auto& desc = m_depthStencilDesc;
|
|
if (desc.DepthFunc != comparisonFunc || desc.DepthWriteMask != depthWriteMask) {
|
|
desc.DepthFunc = comparisonFunc;
|
|
desc.DepthWriteMask = depthWriteMask;
|
|
m_dirtyDepthStencilState = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setStencil(StencilParams *stencilParams) {
|
|
|
|
static const D3D11_COMPARISON_FUNC decodeStencilFunc[] = {
|
|
D3D11_COMPARISON_NEVER,
|
|
D3D11_COMPARISON_LESS,
|
|
D3D11_COMPARISON_EQUAL,
|
|
D3D11_COMPARISON_LESS_EQUAL,
|
|
D3D11_COMPARISON_GREATER,
|
|
D3D11_COMPARISON_NOT_EQUAL,
|
|
D3D11_COMPARISON_GREATER_EQUAL,
|
|
D3D11_COMPARISON_ALWAYS
|
|
};
|
|
|
|
static const D3D11_STENCIL_OP decodeStencilOp[] = {
|
|
D3D11_STENCIL_OP_KEEP,
|
|
D3D11_STENCIL_OP_ZERO,
|
|
D3D11_STENCIL_OP_REPLACE,
|
|
D3D11_STENCIL_OP_INCR,
|
|
D3D11_STENCIL_OP_INCR_SAT,
|
|
D3D11_STENCIL_OP_DECR,
|
|
D3D11_STENCIL_OP_DECR_SAT,
|
|
D3D11_STENCIL_OP_INVERT
|
|
};
|
|
|
|
if (memcmp(&m_stencilParams, stencilParams, 12) != 0) {
|
|
bool stencilEnable = (stencilParams->m_frontParams & 1) || (stencilParams->m_backParams & 1);
|
|
D3D11_DEPTH_STENCIL_DESC& desc = m_depthStencilDesc;
|
|
desc.StencilEnable = stencilEnable;
|
|
desc.StencilReadMask = stencilParams->m_frontParams >> 24; // byte 3
|
|
desc.StencilWriteMask = stencilParams->m_writeMasks & 0xff; // byte 8
|
|
if (stencilParams->m_frontParams & 1) {
|
|
desc.FrontFace.StencilFunc = decodeStencilFunc[(stencilParams->m_frontParams >> 1) & 7];
|
|
desc.FrontFace.StencilDepthFailOp = decodeStencilOp[(stencilParams->m_frontParams >> 12) & 0xF];
|
|
desc.FrontFace.StencilFailOp = decodeStencilOp[(stencilParams->m_frontParams >> 8) & 0xF];
|
|
desc.FrontFace.StencilPassOp = decodeStencilOp[(stencilParams->m_frontParams >> 4) & 0xF];
|
|
} else {
|
|
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
|
desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
|
|
desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
|
|
desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
|
}
|
|
if (stencilParams->m_backParams & 1) {
|
|
desc.BackFace.StencilFunc = decodeStencilFunc[(stencilParams->m_backParams >> 1) & 7];
|
|
desc.BackFace.StencilDepthFailOp = decodeStencilOp[(stencilParams->m_backParams >> 12) & 0xF];
|
|
desc.BackFace.StencilFailOp = decodeStencilOp[(stencilParams->m_backParams >> 8) & 0xF];
|
|
desc.BackFace.StencilPassOp = decodeStencilOp[(stencilParams->m_backParams >> 4) & 0xF];
|
|
} else {
|
|
desc.BackFace = desc.FrontFace;
|
|
}
|
|
|
|
m_stencilParams = *stencilParams;
|
|
m_dirtyDepthStencilState = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setDepthRange(float minDepth, float maxDepth) {
|
|
(void)minDepth;
|
|
(void)maxDepth;
|
|
// TODO
|
|
}
|
|
|
|
void PCDX11StateManager::setDepthBias(int32_t bias) {
|
|
if (bias != m_rasterizerDesc.DepthBias) {
|
|
m_rasterizerDesc.DepthBias = bias;
|
|
m_dirtyRasterizerState = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setDepthBiasClamp(float biasClamp) {
|
|
if (biasClamp != m_rasterizerDesc.DepthBiasClamp) {
|
|
m_rasterizerDesc.DepthBiasClamp = biasClamp;
|
|
m_dirtyRasterizerState = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setSlopeScaledDepthBias(float slopeScaledDepthBias) {
|
|
if (slopeScaledDepthBias != m_rasterizerDesc.SlopeScaledDepthBias) {
|
|
m_rasterizerDesc.SlopeScaledDepthBias = slopeScaledDepthBias;
|
|
m_dirtyRasterizerState = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setBlendStateAndBlendFactors(
|
|
uint32_t blendState,
|
|
uint8_t alphaThreshold,
|
|
uint32_t blendFactors)
|
|
{
|
|
if ((blendState & 0x7000000) == 0x7000000)
|
|
alphaThreshold = 0;
|
|
|
|
setAlphaThreshold(alphaThreshold);
|
|
|
|
if (blendState != m_blendState) {
|
|
m_blendState = blendState;
|
|
m_dirtyBlendState = true;
|
|
uint32_t shift = 0;
|
|
for (uint32_t i=0; i<4; i++) {
|
|
m_blendFactors[i] = (double)(uint8_t)(blendFactors >> shift);
|
|
shift += 2; // BUG, fixed in Tomb Raider (2013) where shift advances by 8 bit
|
|
}
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setRenderTargetWriteMask(uint32_t mask) {
|
|
mask &= 15;
|
|
if (mask != m_renderTargetWriteMask) {
|
|
m_renderTargetWriteMask = mask;
|
|
m_dirtyBlendState = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setSamplerState(
|
|
uint32_t slot,
|
|
PCDX11BaseTexture *tex,
|
|
uint32_t filter)
|
|
{
|
|
// 0..15 => 0..15
|
|
// 257 => 16
|
|
// 258 => 17
|
|
// 259 => 18
|
|
// 260 => 19
|
|
if (slot >= 0x10) slot -= 0xF1;
|
|
|
|
uint32_t repeat = tex->wrapMode & 7;
|
|
|
|
if (repeat != m_samplerRepeat[slot] || filter != m_samplerFilter[slot]) {
|
|
m_samplerRepeat[slot] = repeat;
|
|
m_samplerFilter[slot] = filter;
|
|
|
|
uint32_t maxAnisotropy = 1;
|
|
D3D11_FILTER d3dfilter;
|
|
switch (filter) {
|
|
case 1:
|
|
d3dfilter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
|
break;
|
|
case 2:
|
|
d3dfilter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
|
break;
|
|
case 3: // 1
|
|
case 4: // 2
|
|
case 6: // 4
|
|
case 10: // 8
|
|
case 18: // 16
|
|
d3dfilter = D3D11_FILTER_ANISOTROPIC;
|
|
maxAnisotropy = filter - 2;
|
|
break;
|
|
default:
|
|
d3dfilter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
|
break;
|
|
}
|
|
|
|
D3D11_SAMPLER_DESC samplerDesc = {};
|
|
samplerDesc.Filter = d3dfilter;
|
|
samplerDesc.AddressU = (repeat & 1) ? D3D11_TEXTURE_ADDRESS_WRAP : D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
samplerDesc.AddressV = (repeat & 2) ? D3D11_TEXTURE_ADDRESS_WRAP : D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
samplerDesc.AddressW = (repeat & 4) ? D3D11_TEXTURE_ADDRESS_WRAP : D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
samplerDesc.MipLODBias = 0.0;
|
|
samplerDesc.MaxAnisotropy = maxAnisotropy;
|
|
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
|
samplerDesc.BorderColor[0] = 0.0f;
|
|
samplerDesc.BorderColor[1] = 0.0f;
|
|
samplerDesc.BorderColor[2] = 0.0f;
|
|
samplerDesc.BorderColor[3] = 0.0f;
|
|
samplerDesc.MinLOD = -FLT_MAX;
|
|
samplerDesc.MaxLOD = FLT_MAX;
|
|
|
|
if (slot == 14) {
|
|
samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS;
|
|
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
|
|
}
|
|
|
|
// TODO: cache samplers
|
|
ID3D11SamplerState *samplerState;
|
|
m_device->CreateSamplerState(&samplerDesc, &samplerState);
|
|
|
|
if (samplerState != m_samplers[slot]) {
|
|
m_dirtySamplersFirst = std::min<uint8_t>(m_dirtySamplersFirst, slot);
|
|
m_dirtySamplersLast = std::max<uint8_t>(m_dirtySamplersLast, slot);
|
|
m_dirtySamplers = true;
|
|
m_samplers[slot] = samplerState;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setTextureAndSampler(
|
|
uint32_t slot,
|
|
PCDX11BaseTexture *tex,
|
|
uint32_t filter,
|
|
float unknown)
|
|
{
|
|
// 0..15 => 0..15
|
|
// 257 => 16
|
|
// 258 => 17
|
|
// 259 => 18
|
|
// 260 => 19
|
|
uint32_t originalSlot = slot;
|
|
if (slot >= 0x10) slot -= 0xF1;
|
|
if (!m_device) return;
|
|
|
|
// TODO: logic to avoid binding a texture currently used as a rendertarget
|
|
if (tex != m_textures[slot]) {
|
|
if (auto srv = tex ? tex->createShaderResourceView() : nullptr) {
|
|
m_textureViews[slot] = srv;
|
|
if (filter > tex->maxFilter)
|
|
filter = tex->maxFilter;
|
|
setSamplerState(originalSlot, tex, filter);
|
|
m_textureResources[slot] = tex->getTextureResource();
|
|
} else {
|
|
m_textureViews[slot] = nullptr;
|
|
m_textureResources[slot] = nullptr;
|
|
}
|
|
m_dirtyShaderResourcesFirst = std::min<uint8_t>(m_dirtyShaderResourcesFirst, slot);
|
|
m_dirtyShaderResourcesLast = std::max<uint8_t>(m_dirtyShaderResourcesLast, slot);
|
|
m_dirtyShaderResources = true;
|
|
m_textures[slot] = tex;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setPsConstantBuffer(uint32_t slot, PCDX11ConstantBuffer *cb) {
|
|
if (cb != m_constantBufferPs[slot]) {
|
|
ID3D11Buffer *buffer = cb->getBuffer();
|
|
m_deviceContext->PSSetConstantBuffers(slot, 1, &buffer);
|
|
m_constantBufferPs[slot] = cb;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setVsConstantBuffer(uint32_t slot, PCDX11ConstantBuffer *cb) {
|
|
if (cb != m_constantBufferVs[slot]) {
|
|
ID3D11Buffer *buffer = cb->getBuffer();
|
|
m_deviceContext->VSSetConstantBuffers(slot, 1, &buffer);
|
|
m_constantBufferVs[slot] = cb;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setCommonConstantBuffers() {
|
|
setVsConstantBuffer(0, m_uberConstantBuffer[0]); // WorldBuffer
|
|
setVsConstantBuffer(1, m_uberConstantBuffer[3]); // SkinningBuffer
|
|
setVsConstantBuffer(2, m_uberConstantBuffer[1]); // SceneBuffer
|
|
// 3 StreamDeclBuffer
|
|
// 4 MaterialBuffer
|
|
setVsConstantBuffer(5, m_uberConstantBuffer[4]);
|
|
setVsConstantBuffer(6, m_uberConstantBuffer[5]);
|
|
|
|
setPsConstantBuffer(0, m_uberConstantBuffer[0]); // WorldBuffer
|
|
setPsConstantBuffer(1, m_uberConstantBuffer[2]); // DrawableBuffer
|
|
setPsConstantBuffer(2, m_uberConstantBuffer[1]); // SceneBuffer
|
|
// 3 MaterialBuffer
|
|
setPsConstantBuffer(5, m_uberConstantBuffer[4]); // LightBuffer / InstanceBuffer
|
|
setPsConstantBuffer(6, m_uberConstantBuffer[5]);
|
|
|
|
// setHsConstantBuffer(0, m_uberConstantBuffer[0]);
|
|
// setHsConstantBuffer(1, m_uberConstantBuffer[6]);
|
|
// setHsConstantBuffer(2, m_uberConstantBuffer[1]);
|
|
|
|
// setDsConstantBuffer(0, m_uberConstantBuffer[0]);
|
|
// setDsConstantBuffer(1, m_uberConstantBuffer[6]);
|
|
// setDsConstantBuffer(2, m_uberConstantBuffer[1]);
|
|
}
|
|
|
|
PCDX11UberConstantBuffer& PCDX11StateManager::accessCommonCB(uint32_t i) {
|
|
m_dirtyUberCBs[i] = true;
|
|
m_dirtyConstantBuffers = true;
|
|
return *m_uberConstantBuffer[i];
|
|
}
|
|
|
|
void PCDX11StateManager::setAlphaThreshold(uint8_t threshold) {
|
|
float alphaThreshold = threshold / 255.0;
|
|
if (m_alphaThreshold != alphaThreshold) {
|
|
m_alphaThreshold = alphaThreshold;
|
|
float row[4] = {alphaThreshold, 0.0f, 0.0f, 0.0f};
|
|
accessCommonCB(2).assignRow(3, row, 1); // DrawableBuffer::AlphaThreshold
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setFogColor(float *color) {
|
|
if (m_fogColor[0] != color[0] ||
|
|
m_fogColor[1] != color[1] ||
|
|
m_fogColor[2] != color[2] ||
|
|
m_fogColor[3] != color[3])
|
|
{
|
|
m_fogColor[0] = color[0];
|
|
m_fogColor[1] = color[1];
|
|
m_fogColor[2] = color[2];
|
|
m_fogColor[3] = color[3];
|
|
accessCommonCB(2).assignRow(0, color, 1); // DrawableBuffer::FogColor
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setOpacity(float opacity) {
|
|
if (m_materialOpacity != opacity) {
|
|
m_materialOpacity = opacity;
|
|
float row[4] = {opacity, 0.0f, 0.0f, 0.0f};
|
|
accessCommonCB(2).assignRow(2, row, 1); // DrawableBuffer::MaterialOpacity
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setWorldMatrix(Matrix& worldMatrix) {
|
|
if (m_worldMatrix != worldMatrix) {
|
|
m_worldMatrix = worldMatrix;
|
|
m_dirtyWorldMatrix = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setViewMatrix(Matrix& viewMatrix) {
|
|
if (m_viewMatrix != viewMatrix) {
|
|
m_viewMatrix = viewMatrix;
|
|
m_dirtyViewMatrix = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setProjectMatrix(Matrix& projectMatrix) {
|
|
if (m_projectMatrix != projectMatrix) {
|
|
m_projectMatrix = projectMatrix;
|
|
m_dirtyProjectMatrix = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::setProjectMatrixPtr(Matrix* projectMatrixPtr) {
|
|
if (m_projectMatrixPtr != projectMatrixPtr) {
|
|
m_projectMatrixPtr = projectMatrixPtr;
|
|
m_dirtyProjectMatrix = true;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::updateMatrices() {
|
|
if (m_dirtyWorldMatrix)
|
|
accessCommonCB(0).assignMatrix(4, m_worldMatrix); // WorldBuffer::World
|
|
|
|
if (m_dirtyViewMatrix)
|
|
accessCommonCB(1).assignMatrix(0, m_viewMatrix); // SceneBuffer::View
|
|
|
|
if (m_dirtyViewMatrix || m_dirtyProjectMatrix) {
|
|
|
|
Matrix *projectMatrix = &m_projectMatrix;
|
|
if (m_projectMatrixPtr)
|
|
projectMatrix = m_projectMatrixPtr;
|
|
// TODO: build project matrix right here depending on byte5E9
|
|
|
|
m_viewProjectMatrix = *projectMatrix * m_viewMatrix;
|
|
|
|
accessCommonCB(0).assignMatrix(8, m_viewProjectMatrix); // WorldBuffer::ViewProject
|
|
|
|
}
|
|
|
|
if (m_dirtyWorldMatrix || m_dirtyViewMatrix || m_dirtyProjectMatrix) {
|
|
|
|
Matrix worldViewProject = m_viewProjectMatrix * m_worldMatrix;
|
|
|
|
accessCommonCB(0).assignMatrix(0, worldViewProject);
|
|
|
|
m_dirtyWorldMatrix = false;
|
|
m_dirtyViewMatrix = false;
|
|
m_dirtyProjectMatrix = false;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::updateRasterizerState() {
|
|
|
|
if (m_dirtyRasterizerState) {
|
|
ID3D11RasterizerState *rasterizerState;
|
|
if (auto it = m_rasterizerStates.find(m_rasterizerDesc); it != m_rasterizerStates.end())
|
|
rasterizerState = it->second;
|
|
else {
|
|
m_device->CreateRasterizerState(
|
|
&m_rasterizerDesc,
|
|
&rasterizerState);
|
|
m_rasterizerStates[m_rasterizerDesc] = rasterizerState;
|
|
}
|
|
|
|
m_deviceContext->RSSetState(rasterizerState);
|
|
|
|
m_dirtyRasterizerState = false;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::updateDepthStencilState() {
|
|
|
|
if (m_dirtyDepthStencilState) {
|
|
ID3D11DepthStencilState *depthStencilState;
|
|
if (auto it = m_depthStencilStates.find(m_depthStencilDesc); it != m_depthStencilStates.end())
|
|
depthStencilState = it->second;
|
|
else {
|
|
m_device->CreateDepthStencilState(
|
|
&m_depthStencilDesc,
|
|
&depthStencilState);
|
|
m_depthStencilStates[m_depthStencilDesc] = depthStencilState;
|
|
}
|
|
|
|
m_deviceContext->OMSetDepthStencilState(
|
|
depthStencilState,
|
|
(m_stencilParams.m_frontParams >> 16) & 0xff // byte 2
|
|
);
|
|
|
|
m_dirtyDepthStencilState = false;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::updateBlendState() {
|
|
|
|
D3D11_BLEND_OP blendOps[] = {
|
|
D3D11_BLEND_OP_ADD,
|
|
D3D11_BLEND_OP_SUBTRACT,
|
|
D3D11_BLEND_OP_REV_SUBTRACT,
|
|
D3D11_BLEND_OP_MIN,
|
|
D3D11_BLEND_OP_MAX
|
|
};
|
|
|
|
D3D11_BLEND colorBlends[] = {
|
|
D3D11_BLEND_ZERO,
|
|
D3D11_BLEND_ONE,
|
|
D3D11_BLEND_SRC_COLOR,
|
|
D3D11_BLEND_INV_SRC_COLOR,
|
|
D3D11_BLEND_SRC_ALPHA,
|
|
D3D11_BLEND_INV_SRC_ALPHA,
|
|
D3D11_BLEND_DEST_COLOR,
|
|
D3D11_BLEND_INV_DEST_COLOR,
|
|
D3D11_BLEND_DEST_ALPHA,
|
|
D3D11_BLEND_INV_DEST_ALPHA,
|
|
D3D11_BLEND_BLEND_FACTOR,
|
|
D3D11_BLEND_INV_BLEND_FACTOR
|
|
};
|
|
|
|
D3D11_BLEND alphaBlends[] = {
|
|
D3D11_BLEND_ZERO,
|
|
D3D11_BLEND_ONE,
|
|
D3D11_BLEND_SRC_ALPHA,
|
|
D3D11_BLEND_INV_SRC_ALPHA,
|
|
D3D11_BLEND_SRC_ALPHA,
|
|
D3D11_BLEND_INV_SRC_ALPHA,
|
|
D3D11_BLEND_DEST_ALPHA,
|
|
D3D11_BLEND_INV_DEST_ALPHA,
|
|
D3D11_BLEND_DEST_ALPHA,
|
|
D3D11_BLEND_INV_DEST_ALPHA,
|
|
D3D11_BLEND_BLEND_FACTOR,
|
|
D3D11_BLEND_INV_BLEND_FACTOR
|
|
};
|
|
|
|
if (m_dirtyBlendState) {
|
|
ID3D11BlendState *blendState;
|
|
uint64_t key = ((uint64_t)m_renderTargetWriteMask) << 32 | m_blendState;
|
|
if (auto it = m_blendStates.find(key); it != m_blendStates.end())
|
|
blendState = it->second;
|
|
else {
|
|
D3D11_BLEND_DESC blendDesc;
|
|
memset(&blendDesc, 0, sizeof(blendDesc));
|
|
|
|
// set to d3d default
|
|
blendDesc.AlphaToCoverageEnable = false;
|
|
blendDesc.IndependentBlendEnable = false;
|
|
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
|
|
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
|
|
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
|
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
|
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
|
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
|
|
|
//
|
|
blendDesc.RenderTarget[0].RenderTargetWriteMask = m_renderTargetWriteMask;
|
|
|
|
if ((m_blendState & 1) || m_renderTargetWriteMask != 15) {
|
|
blendDesc.RenderTarget[0].BlendEnable = true;
|
|
blendDesc.RenderTarget[0].BlendOp = blendOps[(m_blendState >> 1) & 7];
|
|
blendDesc.RenderTarget[0].SrcBlend = colorBlends[(m_blendState >> 4) & 15];
|
|
blendDesc.RenderTarget[0].DestBlend = colorBlends[(m_blendState >> 8) & 15];
|
|
|
|
if (m_blendState & 0x1000) {
|
|
blendDesc.RenderTarget[0].BlendOpAlpha = blendOps[(m_blendState >> 13) & 7];
|
|
blendDesc.RenderTarget[0].SrcBlendAlpha = alphaBlends[(m_blendState >> 16) & 15];
|
|
blendDesc.RenderTarget[0].DestBlendAlpha = alphaBlends[(m_blendState >> 20) & 15];
|
|
|
|
} else {
|
|
// copy from color settings
|
|
blendDesc.RenderTarget[0].BlendOpAlpha = blendDesc.RenderTarget[0].BlendOp;
|
|
blendDesc.RenderTarget[0].SrcBlendAlpha = alphaBlends[(m_blendState >> 4) & 15];
|
|
blendDesc.RenderTarget[0].DestBlendAlpha = alphaBlends[(m_blendState >> 8) & 15];
|
|
}
|
|
|
|
} else {
|
|
blendDesc.RenderTarget[0].BlendEnable = false;
|
|
}
|
|
|
|
HRESULT r = m_device->CreateBlendState(
|
|
&blendDesc,
|
|
&blendState);
|
|
if (r != 0)
|
|
cdc::FatalError("Couldn't create blend state %08x", m_blendState);
|
|
m_blendStates[key] = blendState;
|
|
}
|
|
|
|
m_deviceContext->OMSetBlendState(
|
|
blendState,
|
|
m_blendFactors,
|
|
/*sampleMask=*/ 0xffffffff);
|
|
|
|
m_dirtyBlendState = false;
|
|
}
|
|
}
|
|
|
|
void PCDX11StateManager::updateShaderResources() {
|
|
unsigned begin = m_dirtyShaderResourcesFirst;
|
|
unsigned end = m_dirtyShaderResourcesLast + 1;
|
|
|
|
unsigned psBegin = std::clamp(begin, 0u, 16u);
|
|
unsigned psEnd = std::clamp(end, 0u, 16u);
|
|
|
|
if (psBegin < psEnd)
|
|
m_deviceContext->PSSetShaderResources(
|
|
psBegin, psEnd-psBegin, &m_textureViews[psBegin]);
|
|
|
|
unsigned vsBegin = std::clamp(begin, 16u, 20u);
|
|
unsigned vsEnd = std::clamp(end, 16u, 20u);
|
|
|
|
if (vsBegin < vsEnd)
|
|
m_deviceContext->VSSetShaderResources(
|
|
vsBegin-16, vsEnd-vsBegin, &m_textureViews[vsBegin]);
|
|
|
|
m_dirtyShaderResources = false;
|
|
m_dirtyShaderResourcesFirst = 20;
|
|
m_dirtyShaderResourcesLast = 0;
|
|
}
|
|
|
|
void PCDX11StateManager::updateSamplers() {
|
|
unsigned begin = m_dirtySamplersFirst;
|
|
unsigned end = m_dirtySamplersLast + 1;
|
|
|
|
unsigned psBegin = std::clamp(begin, 0u, 16u);
|
|
unsigned psEnd = std::clamp(end, 0u, 16u);
|
|
|
|
if (psBegin < psEnd)
|
|
m_deviceContext->PSSetSamplers(
|
|
psBegin, psEnd-psBegin, &m_samplers[psBegin]);
|
|
|
|
unsigned vsBegin = std::clamp(begin, 16u, 20u);
|
|
unsigned vsEnd = std::clamp(end, 16u, 20u);
|
|
|
|
if (vsBegin < vsEnd)
|
|
m_deviceContext->VSSetSamplers(
|
|
vsBegin-16, vsEnd-vsBegin, &m_samplers[vsBegin]);
|
|
|
|
m_dirtySamplers = false;
|
|
m_dirtySamplersFirst = 20;
|
|
m_dirtySamplersLast = 0;
|
|
}
|
|
|
|
void PCDX11StateManager::updateConstantBuffers() {
|
|
for (int i = 0; i < 7; i++)
|
|
m_uberConstantBuffer[i]->syncBuffer(m_deviceContext);
|
|
m_dirtyConstantBuffers = false;
|
|
}
|
|
|
|
void PCDX11StateManager::pushRenderTargets(
|
|
PCDX11RenderTarget *renderTarget,
|
|
PCDX11DepthBuffer *depthBuffer)
|
|
{
|
|
uint32_t &i = m_renderTargetStackIndex;
|
|
m_renderTargetStack[i] = m_renderTarget;
|
|
m_depthBufferStack[i] = m_depthBuffer;
|
|
i++;
|
|
|
|
updateRenderTargets(renderTarget, depthBuffer);
|
|
}
|
|
|
|
void PCDX11StateManager::popRenderTargets() {
|
|
PCDX11RenderTarget *renderTarget = nullptr;
|
|
PCDX11DepthBuffer *depthBuffer = nullptr;
|
|
if (uint32_t &i = m_renderTargetStackIndex; --i) {
|
|
renderTarget = m_renderTargetStack[i];
|
|
depthBuffer = m_depthBufferStack[i];
|
|
}
|
|
|
|
updateRenderTargets(renderTarget, depthBuffer);
|
|
}
|
|
|
|
void PCDX11StateManager::updateRenderTargets(
|
|
PCDX11RenderTarget *renderTarget,
|
|
PCDX11DepthBuffer *depthBuffer)
|
|
{
|
|
// TODO
|
|
m_renderTarget = renderTarget;
|
|
m_depthBuffer = depthBuffer;
|
|
|
|
ID3D11RenderTargetView *renderTargetView = renderTarget ? renderTarget->getRenderTargetView() : nullptr;
|
|
ID3D11DepthStencilView *depthStencilView = depthBuffer ?
|
|
depthBuffer->isLocked ? depthBuffer->getRODepthStencilView() : depthBuffer->getRWDepthStencilView() : nullptr;
|
|
m_deviceContext->OMSetRenderTargets(
|
|
!!renderTargetView,
|
|
&renderTargetView,
|
|
depthStencilView);
|
|
}
|
|
|
|
void PCDX11StateManager::updateRenderState() {
|
|
if (m_dirtyRasterizerState)
|
|
updateRasterizerState();
|
|
if (m_dirtyDepthStencilState)
|
|
updateDepthStencilState();
|
|
if (m_dirtyBlendState)
|
|
updateBlendState();
|
|
if (m_dirtyShaderResources)
|
|
updateShaderResources();
|
|
if (m_dirtySamplers)
|
|
updateSamplers();
|
|
if (m_dirtyConstantBuffers)
|
|
updateConstantBuffers();
|
|
}
|
|
|
|
void PCDX11StateManager::updateViewport() {
|
|
// TODO
|
|
}
|
|
|
|
void PCDX11StateManager::setComputeShader(PCDX11ComputeShader *computeShader) {
|
|
if (!computeShader->m_d3dShader)
|
|
computeShader->createD3DShader();
|
|
m_deviceContext->CSSetShader(computeShader->m_d3dShader, nullptr, 0);
|
|
}
|
|
|
|
void PCDX11StateManager::setComputeShaderTexture(uint32_t slot, PCDX11BaseTexture *tex) {
|
|
ID3D11ShaderResourceView *srv = tex ? tex->createShaderResourceView() : nullptr;
|
|
m_deviceContext->CSSetShaderResources(slot, 1, &srv);
|
|
}
|
|
|
|
void PCDX11StateManager::setComputeShaderUAV(uint32_t slot, PCDX11BaseTexture *tex) {
|
|
ID3D11UnorderedAccessView *uav = tex ? tex->createUnorderedAccessView() : nullptr;
|
|
unsigned negOne = -1;
|
|
m_deviceContext->CSSetUnorderedAccessViews(slot, 1, &uav, &negOne);
|
|
}
|
|
|
|
void PCDX11StateManager::setComputeShaderCB(uint32_t slot, PCDX11ConstantBuffer *cb) {
|
|
ID3D11Buffer *buffer = cb ? cb->getBuffer() : nullptr;
|
|
m_deviceContext->CSSetConstantBuffers(slot, 1, &buffer);
|
|
}
|
|
|
|
void PCDX11StateManager::dispatch(uint32_t x, uint32_t y, uint32_t z) {
|
|
m_deviceContext->Dispatch(x, y, z);
|
|
}
|
|
|
|
bool PCDX11StateManager::internalCreate() {
|
|
|
|
m_device = deviceManager->getD3DDevice();
|
|
m_indexBufferD3D = nullptr;
|
|
m_vertexBufferD3D = nullptr;
|
|
m_streamDecl = nullptr;
|
|
m_pixelShader = nullptr;
|
|
m_vertexShader = nullptr;
|
|
// TODO: hull shader
|
|
// TODO: domain shader
|
|
|
|
m_rasterizerDesc.FillMode = D3D11_FILL_SOLID;
|
|
m_rasterizerDesc.CullMode = D3D11_CULL_BACK;
|
|
m_rasterizerDesc.FrontCounterClockwise = false;
|
|
m_rasterizerDesc.DepthBias = 0;
|
|
m_rasterizerDesc.DepthBiasClamp = 1.0;
|
|
m_rasterizerDesc.SlopeScaledDepthBias = 0.0;
|
|
m_rasterizerDesc.DepthClipEnable = true;
|
|
m_rasterizerDesc.ScissorEnable = false;
|
|
m_rasterizerDesc.MultisampleEnable = false;
|
|
m_rasterizerDesc.AntialiasedLineEnable = false;
|
|
|
|
memset((void*)&m_depthStencilDesc, 0, sizeof(m_depthStencilDesc));
|
|
m_depthStencilDesc.DepthEnable = true;
|
|
m_depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
|
m_depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
|
|
m_depthStencilDesc.StencilEnable = false;
|
|
m_depthStencilDesc.StencilReadMask = 255;
|
|
m_depthStencilDesc.StencilWriteMask = 255;
|
|
m_renderTargetWriteMask = 0;
|
|
|
|
// TODO: stencilParams
|
|
|
|
reset();
|
|
// TODO: clipPlanes
|
|
|
|
m_renderTargetStackIndex = 0;
|
|
|
|
m_dirtyUberCBs[0] = false;
|
|
m_dirtyUberCBs[1] = false;
|
|
m_dirtyUberCBs[2] = false;
|
|
m_dirtyUberCBs[3] = false;
|
|
m_dirtyUberCBs[4] = false;
|
|
m_dirtyUberCBs[5] = false;
|
|
m_dirtyUberCBs[6] = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void PCDX11StateManager::internalRelease() {}
|
|
|
|
}
|