1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00

Fixed rendering with non-default texture coordinate indexes

Fixes rendering issues in Ultima IX when MultiPassChromakey=1 or 2.
This commit is contained in:
narzoul 2024-05-16 23:58:00 +02:00
parent 2da9c87a21
commit f0946f2437
4 changed files with 100 additions and 16 deletions

View File

@ -90,8 +90,8 @@ namespace D3dDdi
, m_vertexDecl(nullptr)
, m_changedStates(0)
, m_maxChangedTextureStage(0)
, m_texCoordIndexes(0)
, m_changedTextureStageStates{}
, m_vsVertexFixup(createVertexShader(g_vsVertexFixup))
, m_textureResource{}
, m_pixelShader(nullptr)
, m_isLocked(false)
@ -187,6 +187,7 @@ namespace D3dDdi
{
m_current.textureStageState[i].fill(UNINITIALIZED_STATE);
m_current.textureStageState[i][D3DDDITSS_TEXCOORDINDEX] = i;
m_texCoordIndexes |= i << (i * 3);
// When ADDRESSU or ADDRESSV is set to CLAMP, their value is overridden by D3DTSS_ADDRESS.
// Setting this to CLAMP makes them behave as expected, instead of as WRAP,
@ -224,11 +225,11 @@ namespace D3dDdi
updateConfig();
}
std::unique_ptr<void, ResourceDeleter> DeviceState::createVertexShader(const BYTE* code, UINT size)
std::unique_ptr<void, ResourceDeleter> DeviceState::createVertexShader(const UINT* code, UINT size)
{
D3DDDIARG_CREATEVERTEXSHADERFUNC data = {};
data.Size = size;
if (FAILED(m_device.getOrigVtable().pfnCreateVertexShaderFunc(m_device, &data, reinterpret_cast<const UINT*>(code))))
if (FAILED(m_device.getOrigVtable().pfnCreateVertexShaderFunc(m_device, &data, code)))
{
return nullptr;
}
@ -326,6 +327,26 @@ namespace D3dDdi
return m_vertexDecl ? *m_vertexDecl : emptyDecl;
}
HANDLE DeviceState::getVsVertexFixup()
{
auto it = m_vsVertexFixups.find(m_texCoordIndexes);
if (it != m_vsVertexFixups.end())
{
return it->second.get();
}
std::array<UINT, 8> texCoordIndexes = {};
for (UINT i = 0; i < 8; ++i)
{
texCoordIndexes[i] = m_app.textureStageState[i][D3DDDITSS_TEXCOORDINDEX];
}
D3dDdi::ShaderAssembler shaderAssembler(reinterpret_cast<const UINT*>(g_vsVertexFixup), sizeof(g_vsVertexFixup));
shaderAssembler.applyTexCoordIndexes(texCoordIndexes);
return m_vsVertexFixups.emplace(m_texCoordIndexes,
createVertexShader(shaderAssembler.getTokens().data(), shaderAssembler.getTokens().size() * 4)).first->second.get();
}
bool DeviceState::isColorKeyUsed()
{
if (!m_app.renderState[D3DDDIRS_COLORKEYENABLE])
@ -669,6 +690,12 @@ namespace D3dDdi
m_changedRenderStates.set(D3DDDIRS_COLORKEYENABLE);
m_changedStates |= CS_RENDER_STATE;
}
else if (D3DDDITSS_TEXCOORDINDEX == data->State)
{
m_texCoordIndexes &= ~(7 << (data->Stage * 3));
m_texCoordIndexes |= data->Value << (data->Stage * 3);
m_changedStates |= CS_SHADER;
}
m_app.textureStageState[data->Stage][data->State] = data->Value;
m_changedTextureStageStates[data->Stage].set(data->State);
@ -1203,14 +1230,7 @@ namespace D3dDdi
{
setPixelShader(mapPixelShader(m_app.pixelShader));
setVertexShaderDecl(m_app.vertexShaderDecl);
if (getVertexDecl().isTransformed)
{
setVertexShaderFunc(m_vsVertexFixup.get());
}
else
{
setVertexShaderFunc(m_app.vertexShaderFunc);
}
setVertexShaderFunc(getVertexDecl().isTransformed ? getVsVertexFixup() : m_app.vertexShaderFunc);
}
void DeviceState::updateStreamSource()

View File

@ -156,7 +156,6 @@ namespace D3dDdi
Resource* getTextureResource(UINT stage);
UINT getTextureStageCount() const;
const VertexDecl& getVertexDecl() const;
HANDLE getVertexFixupDecl() const { return m_vsVertexFixup.get(); }
bool isLocked() const { return m_isLocked; }
void onDestroyResource(Resource* resource, HANDLE resourceHandle);
void updateConfig();
@ -183,13 +182,14 @@ namespace D3dDdi
template <int N>
std::unique_ptr<void, ResourceDeleter> createVertexShader(const BYTE(&code)[N])
{
return createVertexShader(code, N);
return createVertexShader(reinterpret_cast<const UINT*>(code), N);
}
std::unique_ptr<void, ResourceDeleter> DeviceState::createVertexShader(const BYTE* code, UINT size);
std::unique_ptr<void, ResourceDeleter> DeviceState::createVertexShader(const UINT* code, UINT size);
HRESULT deleteShader(HANDLE shader, HANDLE State::* shaderMember,
HRESULT(APIENTRY* origDeleteShaderFunc)(HANDLE, HANDLE));
HANDLE getVsVertexFixup();
bool isColorKeyUsed();
HANDLE mapPixelShader(HANDLE shader);
UINT mapRsValue(D3DDDIRENDERSTATETYPE state, UINT value);
@ -245,10 +245,10 @@ namespace D3dDdi
VertexDecl* m_vertexDecl;
UINT m_changedStates;
UINT m_maxChangedTextureStage;
UINT m_usedTextureStages;
UINT m_texCoordIndexes;
BitSet<D3DDDIRS_ZENABLE, D3DDDIRS_BLENDOPALPHA> m_changedRenderStates;
std::array<BitSet<D3DDDITSS_TEXTUREMAP, D3DDDITSS_TEXTURECOLORKEYVAL>, 8> m_changedTextureStageStates;
std::unique_ptr<void, ResourceDeleter> m_vsVertexFixup;
std::map<UINT, std::unique_ptr<void, ResourceDeleter>> m_vsVertexFixups;
std::array<Resource*, 8> m_textureResource;
std::map<HANDLE, PixelShader> m_pixelShaders;
PixelShader* m_pixelShader;

View File

@ -359,6 +359,68 @@ namespace D3dDdi
return true;
}
void ShaderAssembler::applyTexCoordIndexes(const std::array<UINT, 8>& texCoordIndexes)
{
LOG_FUNC("ShaderAssembler::applyTexCoordIndex", Compat::array(texCoordIndexes.data(), texCoordIndexes.size()));
LOG_DEBUG << "Original bytecode: " << Compat::hexDump(m_tokens.data(), m_tokens.size() * 4);
LOG_DEBUG << disassemble();
RestorePos restorePos(m_pos);
m_pos = 0;
std::array<UINT, 8> tcIndexToRegNum = {};
std::array<UINT, 16> regNumToTcIndex = {};
regNumToTcIndex.fill(UINT_MAX);
while (nextInstruction())
{
const auto instruction = getToken<InstructionToken>();
if (D3DSIO_DCL == instruction.opcode)
{
const auto usage = getToken<UINT32>(1);
if (D3DDECLUSAGE_TEXCOORD == (usage & D3DSP_DCL_USAGE_MASK))
{
const auto tcIndex = (usage & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
const auto dst = getToken<UINT32>(2);
const auto regNum = dst & D3DSP_REGNUM_MASK;
tcIndexToRegNum[tcIndex] = regNum;
regNumToTcIndex[regNum] = tcIndex;
}
continue;
}
const auto it = g_instructionMap.find(instruction.opcode);
if (it == g_instructionMap.end())
{
continue;
}
for (UINT i = 0; i < it->second.srcCount; ++i)
{
UINT& src = m_tokens[m_pos + 1 + it->second.dstCount + i];
const auto regType = getRegisterType(src);
if (D3DSPR_INPUT != regType)
{
continue;
}
const auto origRegNum = src & D3DSP_REGNUM_MASK;
const auto origTcIndex = regNumToTcIndex[origRegNum];
if (origTcIndex >= texCoordIndexes.size())
{
continue;
}
const auto mappedTcIndex = texCoordIndexes[origTcIndex] & 7;
const auto mappedRegNum = tcIndexToRegNum[mappedTcIndex];
src &= ~D3DSP_REGNUM_MASK;
src |= mappedRegNum;
}
}
LOG_DEBUG << "Modified bytecode: " << Compat::hexDump(m_tokens.data(), m_tokens.size() * 4);
LOG_DEBUG << disassemble();
}
std::string ShaderAssembler::disassemble()
{
if (Config::Settings::LogLevel::DEBUG != Compat::Log::getLogLevel())

View File

@ -1,5 +1,6 @@
#pragma once
#include <array>
#include <ostream>
#include <set>
#include <string>
@ -15,6 +16,7 @@ namespace D3dDdi
ShaderAssembler(const UINT* code, DWORD size);
bool addAlphaTest(UINT alphaRef);
void applyTexCoordIndexes(const std::array<UINT, 8>& texCoordIndexes);
std::string disassemble();
UINT getTextureStageCount();
const std::vector<UINT>& getTokens() const { return m_tokens; }