diff --git a/src/d3d9/d3d9_fixed_function.cpp b/src/d3d9/d3d9_fixed_function.cpp index f9a2a1ce..2af5509e 100644 --- a/src/d3d9/d3d9_fixed_function.cpp +++ b/src/d3d9/d3d9_fixed_function.cpp @@ -1106,6 +1106,17 @@ namespace dxvk { const uint32_t wIndex = 3; uint32_t flags = (m_vsKey.Data.Contents.TransformFlags >> (i * 3)) & 0b111; + + if (flags == D3DTTFF_COUNT1) { + // D3DTTFF_COUNT1 behaves like D3DTTFF_DISABLE on NV and like D3DTTFF_COUNT2 on AMD. + // The Nvidia behavior is easier to implement. + flags = D3DTTFF_DISABLE; + } + + // Passing 0xffffffff results in it getting clamped to the dimensions of the texture coords and getting treated as PROJECTED + // but D3D9 does not apply the transformation matrix. + bool applyTransform = flags >= D3DTTFF_COUNT1 && flags <= D3DTTFF_COUNT4; + uint32_t count; switch (inputFlags) { default: @@ -1116,11 +1127,14 @@ namespace dxvk { count = flags; if (texcoordCount) { // Clamp by the number of elements in the texcoord input. - if (!count || count > texcoordCount) + if (!count || count > texcoordCount) { count = texcoordCount; - } - else + } + } else { + count = 0; flags = D3DTTFF_DISABLE; + applyTransform = false; + } break; case (DXVK_TSS_TCI_CAMERASPACENORMAL >> TCIOffset): @@ -1136,7 +1150,7 @@ namespace dxvk { case (DXVK_TSS_TCI_CAMERASPACEREFLECTIONVECTOR >> TCIOffset): { uint32_t vtx3 = m_module.opVectorShuffle(m_vec3Type, vtx, vtx, 3, indices.data()); vtx3 = m_module.opNormalize(m_vec3Type, vtx3); - + uint32_t reflection = m_module.opReflect(m_vec3Type, vtx3, normal); std::array transformIndices; @@ -1174,9 +1188,8 @@ namespace dxvk { } } - uint32_t type = flags; - if (type != D3DTTFF_DISABLE) { - if (!m_vsKey.Data.Contents.HasPositionT) { + if (applyTransform || (count != 4 && count != 0)) { + if (applyTransform && !m_vsKey.Data.Contents.HasPositionT) { for (uint32_t j = count; j < 4; j++) { // If we're outside the component count of the vertex decl for this texcoord then we pad with zeroes. // Otherwise, pad with ones. @@ -1193,8 +1206,8 @@ namespace dxvk { } // Pad the unused section of it with the value for projection. - uint32_t lastIdx = count - 1; - uint32_t projValue = m_module.opCompositeExtract(m_floatType, transformed, 1, &lastIdx); + uint32_t projIdx = std::max(2u, count - 1); + uint32_t projValue = m_module.opCompositeExtract(m_floatType, transformed, 1, &projIdx); for (uint32_t j = count; j < 4; j++) transformed = m_module.opCompositeInsert(m_vec4Type, projValue, transformed, 1, &j); @@ -1790,22 +1803,17 @@ namespace dxvk { texcoord = m_module.opVectorShuffle(texcoord_t, texcoord, texcoord, texcoordCnt, indices.data()); - uint32_t projIdx = m_fsKey.Stages[i].Contents.ProjectedCount; - if (projIdx == 0 || projIdx > texcoordCnt) { - projIdx = 4; // Always use w if ProjectedCount is 0. - } - --projIdx; - + bool shouldProject = m_fsKey.Stages[i].Contents.Projected; uint32_t projValue = 0; - if (m_fsKey.Stages[i].Contents.Projected) { + if (shouldProject) { + // Always use w, the vertex shader puts the correct value there. + const uint32_t projIdx = 3; projValue = m_module.opCompositeExtract(m_floatType, m_ps.in.TEXCOORD[i], 1, &projIdx); uint32_t insertIdx = texcoordCnt - 1; texcoord = m_module.opCompositeInsert(texcoord_t, projValue, texcoord, 1, &insertIdx); } - bool shouldProject = m_fsKey.Stages[i].Contents.Projected; - if (i != 0 && ( m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAP || m_fsKey.Stages[i - 1].Contents.ColorOp == D3DTOP_BUMPENVMAPLUMINANCE)) {