Merge pull request #15069 from unknownbrackets/swtransform-project

Process projection inside software transform
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2021-10-31 11:09:59 +01:00
commit a3a6bdc19e
16 files changed
+169 -86

No files matched your search

+1
View File
@@ -134,6 +134,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
flippedMatrix = flippedMatrix * g_display_rot_matrix;
}
CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr());
ub->rotation = (float)g_display_rotation;
}
if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) {
+3 -1
View File
@@ -28,7 +28,8 @@ struct UB_VS_FS_Base {
float tex[12];
float uvScaleOffset[4];
float depthRange[4];
float fogCoef[2]; float stencil; float pad0;
// Rotation is used only for software transform.
float fogCoef[2]; float stencil; float rotation;
float matAmbient[4];
float cullRangeMin[4];
float cullRangeMax[4];
@@ -55,6 +56,7 @@ R"( mat4 u_proj;
vec4 u_depthRange;
vec2 u_fogcoef;
float u_stencilReplaceValue;
float u_rotation;
vec4 u_matambientalpha;
vec4 u_cullRangeMin;
vec4 u_cullRangeMax;
+30 -53
View File
@@ -64,16 +64,14 @@ static void SwapUVs(TransformedVertex &a, TransformedVertex &b) {
// Note: 0 is BR and 2 is TL.
static void RotateUV(TransformedVertex v[4], Vec4f tl, Vec4f br, bool flippedY) {
static void RotateUV(TransformedVertex v[4], bool flippedY) {
// We use the transformed tl/br coordinates to figure out whether they're flipped or not.
float ySign = flippedY ? -1.0 : 1.0;
const float invtlw = 1.0f / tl.w;
const float invbrw = 1.0f / br.w;
const float x1 = tl.x * invtlw;
const float x2 = br.x * invbrw;
const float y1 = tl.y * invtlw * ySign;
const float y2 = br.y * invbrw * ySign;
const float x1 = v[2].x;
const float x2 = v[0].x;
const float y1 = v[2].y * ySign;
const float y2 = v[0].y * ySign;
if ((x1 < x2 && y1 < y2) || (x1 > x2 && y1 > y2))
SwapUVs(v[1], v[3]);
@@ -151,6 +149,25 @@ static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) {
return 0;
}
void SoftwareTransform::SetProjMatrix(float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale) {
memcpy(&projMatrix_.m, mtx, 16 * sizeof(float));
if (invertedY) {
projMatrix_.xy = -projMatrix_.xy;
projMatrix_.yy = -projMatrix_.yy;
projMatrix_.zy = -projMatrix_.zy;
projMatrix_.wy = -projMatrix_.wy;
}
if (invertedX) {
projMatrix_.xx = -projMatrix_.xx;
projMatrix_.yx = -projMatrix_.yx;
projMatrix_.zx = -projMatrix_.zx;
projMatrix_.wx = -projMatrix_.wx;
}
projMatrix_.translateAndScale(trans, scale);
}
void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result) {
u8 *decoded = params_.decoded;
TransformedVertex *transformed = params_.transformed;
@@ -196,6 +213,7 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
// TODO: Write to a flexible buffer, we don't always need all four components.
TransformedVertex &vert = transformed[index];
reader.ReadPos(vert.pos);
vert.posw = 1.0f;
if (reader.hasColor0()) {
if (provokeIndOffset != 0 && index + provokeIndOffset < maxIndex) {
@@ -412,14 +430,13 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
fogCoef = (v[2] + fog_end) * fog_slope;
// TODO: Write to a flexible buffer, we don't always need all four components.
memcpy(&transformed[index].x, v, 3 * sizeof(float));
Vec3ByMatrix44(transformed[index].pos, v, projMatrix_.m);
transformed[index].fog = fogCoef;
memcpy(&transformed[index].u, uv, 3 * sizeof(float));
memcpy(&transformed[index].uv, uv, 3 * sizeof(float));
transformed[index].color0_32 = c0.ToRGBA();
transformed[index].color1_32 = c1.ToRGBA();
// The multiplication by the projection matrix is still performed in the vertex shader.
// So is vertex depth rounding, to simulate the 16-bit depth buffer.
// Vertex depth rounding is done in the shader, to simulate the 16-bit depth buffer.
}
}
@@ -428,7 +445,6 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
//
// An alternative option is to simply ditch all the verts except the first and last to create a single
// rectangle out of many. Quite a small optimization though.
// Experiment: Disable on PowerVR (see issue #6290)
// TODO: This bleeds outside the play area in non-buffered mode. Big deal? Probably not.
// TODO: Allow creating a depth clear and a color draw.
bool reallyAClear = false;
@@ -555,37 +571,11 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy
FramebufferManagerCommon *fbman = params_.fbman;
bool useBufferedRendering = fbman->UseBufferedRendering();
bool flippedY = g_Config.iGPUBackend == (int)GPUBackend::OPENGL && !useBufferedRendering;
if (prim != GE_PRIM_RECTANGLES) {
// We can simply draw the unexpanded buffer.
numTrans = vertexCount;
result->drawIndexed = true;
} else {
// Pretty bad hackery where we re-do the transform (in RotateUV) to see if the vertices are flipped in screen space.
// Since we've already got API-specific assumptions (Y direction, etc) baked into the projMatrix (which we arguably shouldn't),
// this gets nasty and very hard to understand.
float flippedMatrix[16];
if (!throughmode) {
memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));
const bool invertedY = flippedY ? (gstate_c.vpHeight < 0) : (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];
}
}
//rectangles always need 2 vertices, disregard the last one if there's an odd number
vertexCount = vertexCount & ~1;
numTrans = 0;
@@ -626,21 +616,8 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy
if (throughmode) {
RotateUVThrough(trans);
} else {
Vec4f tl;
Vec3ByMatrix44(tl.AsArray(), transVtxTL.pos, flippedMatrix);
Vec4f br;
Vec3ByMatrix44(br.AsArray(), transVtxBR.pos, flippedMatrix);
// If both transformed verts are outside Z, cull this rectangle entirely.
constexpr float outsideValue = 1.000030517578125f;
bool tlOutside = fabsf(tl.z / tl.w) >= outsideValue;
bool brOutside = fabsf(br.z / br.w) >= outsideValue;
if (tlOutside && brOutside)
continue;
if (!gstate.isDepthClampEnabled() && (tlOutside || brOutside))
continue;
RotateUV(trans, tl, br, flippedY);
// TODO: Should apply culling here, based on projection depth range.
RotateUV(trans, params_.flippedY);
}
// Triangle: BR-TR-TL
+5 -2
View File
@@ -18,8 +18,8 @@
#pragma once
#include "Common/CommonTypes.h"
#include "VertexDecoderCommon.h"
#include "Common/Math/lin/matrix4x4.h"
#include "GPU/Common/VertexDecoderCommon.h"
class FramebufferManagerCommon;
class TextureCacheCommon;
@@ -56,6 +56,7 @@ struct SoftwareTransformParams {
bool allowClear;
bool allowSeparateAlphaClear;
bool provokeFlatFirst;
bool flippedY;
};
class SoftwareTransform {
@@ -63,10 +64,12 @@ public:
SoftwareTransform(SoftwareTransformParams &params) : params_(params) {
}
void SetProjMatrix(float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale);
void Decode(int prim, u32 vertexType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result);
void DetectOffsetTexture(int maxIndex);
void BuildDrawingParams(int prim, int vertexCount, u32 vertType, u16 *&inds, int &maxIndex, SoftwareTransformResult *result);
protected:
const SoftwareTransformParams &params_;
Lin::Matrix4x4 projMatrix_;
};
+29 -8
View File
@@ -236,11 +236,12 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
if (useHWTransform)
WRITE(p, "layout (location = %d) in vec3 position;\n", (int)PspAttributeLocation::POSITION);
else
// we pass the fog coord in w
WRITE(p, "layout (location = %d) in vec4 position;\n", (int)PspAttributeLocation::POSITION);
if (useHWTransform && hasNormal)
WRITE(p, "layout (location = %d) in vec3 normal;\n", (int)PspAttributeLocation::NORMAL);
if (!useHWTransform && enableFog)
WRITE(p, "layout (location = %d) in float fog;\n", (int)PspAttributeLocation::NORMAL);
if (doTexture && hasTexcoord) {
if (!useHWTransform && doTextureTransform && !isModeThrough) {
@@ -278,9 +279,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, "#pragma warning( disable : 3571 )\n");
if (isModeThrough) {
WRITE(p, "mat4 u_proj_through : register(c%i);\n", CONST_VS_PROJ_THROUGH);
} else {
} else if (useHWTransform) {
WRITE(p, "mat4 u_proj : register(c%i);\n", CONST_VS_PROJ);
// Add all the uniforms we'll need to transform properly.
} else {
WRITE(p, "float u_rotation : register(c%i);\n", CONST_VS_ROTATION);
}
if (enableFog) {
@@ -385,6 +387,9 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
if (lmode) {
WRITE(p, " vec3 color1 : COLOR1;\n");
}
if (enableFog) {
WRITE(p, " float fog : NORMAL;\n");
}
WRITE(p, "};\n");
}
@@ -434,6 +439,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, "%s mediump vec3 normal;\n", compat.attribute);
*attrMask |= 1 << ATTR_NORMAL;
}
if (!useHWTransform && enableFog) {
WRITE(p, "%s highp float fog;\n", compat.attribute);
*attrMask |= 1 << ATTR_NORMAL;
}
if (doTexture && hasTexcoord) {
if (!useHWTransform && doTextureTransform && !isModeThrough) {
@@ -456,10 +465,9 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
if (isModeThrough) {
WRITE(p, "uniform mat4 u_proj_through;\n");
*uniformMask |= DIRTY_PROJTHROUGHMATRIX;
} else {
} else if (useHWTransform) {
WRITE(p, "uniform mat4 u_proj;\n");
*uniformMask |= DIRTY_PROJMATRIX;
// Add all the uniforms we'll need to transform properly.
}
if (useHWTransform) {
@@ -519,6 +527,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, "uniform lowp vec3 u_matemissive;\n");
*uniformMask |= DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE;
}
} else {
WRITE(p, "uniform lowp float u_rotation;\n");
}
if (useHWTransform || !hasColor) {
@@ -763,6 +773,9 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
} else {
WRITE(p, " vec4 position = In.position;\n");
}
if (!useHWTransform && enableFog) {
WRITE(p, " float fog = In.fog;\n");
}
if (enableBones) {
WRITE(p, "%s", boneWeightAttrInitHLSL[numBoneWeights]);
}
@@ -787,16 +800,24 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix);
}
if (enableFog) {
WRITE(p, " %sv_fogdepth = position.w;\n", compat.vsOutPrefix);
WRITE(p, " %sv_fogdepth = fog;\n", compat.vsOutPrefix);
}
if (isModeThrough) {
WRITE(p, " vec4 outPos = mul(u_proj_through, vec4(position.xyz, 1.0));\n");
} else {
// Apply rotation from the uniform.
WRITE(p, " mat4 displayRotation = mat4(\n");
WRITE(p, " u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0), u_rotation == 1.0 ? 1.0 : (u_rotation == 3.0 ? -1.0 : 0.0), 0.0, 0.0,\n");
WRITE(p, " u_rotation == 3.0 ? 1.0 : (u_rotation == 1.0 ? -1.0 : 0.0), u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0), 0.0, 0.0,\n");
WRITE(p, " 0.0, 0.0, 1.0, 0.0,\n");
WRITE(p, " 0.0, 0.0, 0.0, 1.0\n");
WRITE(p, " );\n");
// The viewport is used in this case, so need to compensate for that.
if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj, vec4(position.xyz, 1.0)));\n");
WRITE(p, " vec4 outPos = depthRoundZVP(mul(displayRotation, position));\n");
} else {
WRITE(p, " vec4 outPos = mul(u_proj, vec4(position.xyz, 1.0));\n");
WRITE(p, " vec4 outPos = mul(displayRotation, position);\n");
}
}
} else {
+1
View File
@@ -60,4 +60,5 @@ enum {
CONST_VS_BONE8 = 77,
CONST_VS_CULLRANGEMIN = 80,
CONST_VS_CULLRANGEMAX = 81,
CONST_VS_ROTATION = 82,
};
+20 -4
View File
@@ -61,10 +61,11 @@ enum {
};
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 },
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(TransformedVertex, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(TransformedVertex, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(TransformedVertex, color0), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(TransformedVertex, color1), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32_FLOAT, 0, offsetof(TransformedVertex, fog), D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
DrawEngineD3D11::DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context)
@@ -586,9 +587,24 @@ rotateVBO:
params.allowClear = true;
params.allowSeparateAlphaClear = false; // D3D11 doesn't support separate alpha clears
params.provokeFlatFirst = true;
params.flippedY = false;
// We need correct viewport values in gstate_c already.
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
ViewportAndScissor vpAndScissor;
ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(),
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
vpAndScissor);
}
int maxIndex = indexGen.MaxIndex();
SoftwareTransform swTransform(params);
const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f);
const Lin::Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale);
swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
if (result.action == SW_NOT_READY) {
swTransform.DetectOffsetTexture(maxIndex);
+26 -4
View File
@@ -77,10 +77,11 @@ enum {
enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 };
static const D3DVERTEXELEMENT9 TransformedVertexElements[] = {
{ 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 16, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 0, 28, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
{ 0, 32, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 },
{ 0, offsetof(TransformedVertex, pos), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, offsetof(TransformedVertex, uv), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 0, offsetof(TransformedVertex, color0), D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
{ 0, offsetof(TransformedVertex, color1), D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 },
{ 0, offsetof(TransformedVertex, fog), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
D3DDECL_END()
};
@@ -555,9 +556,30 @@ rotateVBO:
params.allowClear = true;
params.allowSeparateAlphaClear = false;
params.provokeFlatFirst = true;
params.flippedY = false;
// We need correct viewport values in gstate_c already.
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
ViewportAndScissor vpAndScissor;
ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(),
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
vpAndScissor);
}
int maxIndex = indexGen.MaxIndex();
SoftwareTransform swTransform(params);
// Half pixel offset hack.
float xScale = gstate_c.vpWidth < 0 ? -1.0f : 1.0f;
float xOffset = -1.0f / gstate_c.curRTRenderWidth;
float yScale = gstate_c.vpHeight > 0 ? -1.0f : 1.0f;
float yOffset = 1.0f / gstate_c.curRTRenderHeight;
const Lin::Vec3 trans(gstate_c.vpXOffset * xScale + xOffset, gstate_c.vpYOffset * yScale + yOffset, gstate_c.vpZOffset * 0.5f + 0.5f);
const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight > 0, trans, scale);
swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
if (result.action == SW_NOT_READY) {
swTransform.DetectOffsetTexture(maxIndex);
+4 -2
View File
@@ -22,13 +22,14 @@
#include <cmath>
#include <map>
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/Data/Text/I18n.h"
#include "Common/Math/lin/matrix4x4.h"
#include "Common/Math/math_util.h"
#include "Common/Data/Convert/SmallDataConvert.h"
#include "Common/GPU/D3D9/D3D9ShaderCompiler.h"
#include "Common/GPU/thin3d.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/System/Display.h"
#include "Common/Common.h"
#include "Common/Log.h"
@@ -344,6 +345,7 @@ void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) {
ConvertProjMatrixToD3D(flippedMatrix, invertedX, invertedY);
VSSetMatrix(CONST_VS_PROJ, flippedMatrix.getReadPtr());
VSSetFloat(CONST_VS_ROTATION, (float)g_display_rotation);
}
if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) {
Matrix4x4 proj_through;
+17 -1
View File
@@ -118,10 +118,11 @@ void DrawEngineGLES::InitDeviceObjects() {
int vertexSize = sizeof(TransformedVertex);
std::vector<GLRInputLayout::Entry> entries;
entries.push_back({ ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, 0 });
entries.push_back({ ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, offsetof(TransformedVertex, x) });
entries.push_back({ ATTR_TEXCOORD, 3, GL_FLOAT, GL_FALSE, vertexSize, offsetof(TransformedVertex, u) });
entries.push_back({ ATTR_COLOR0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, offsetof(TransformedVertex, color0) });
entries.push_back({ ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, offsetof(TransformedVertex, color1) });
entries.push_back({ ATTR_NORMAL, 1, GL_FLOAT, GL_FALSE, vertexSize, offsetof(TransformedVertex, fog) });
softwareInputLayout_ = render_->CreateInputLayout(entries);
}
@@ -563,6 +564,15 @@ void DrawEngineGLES::DoFlush() {
params.allowClear = true;
params.allowSeparateAlphaClear = true;
params.provokeFlatFirst = false;
params.flippedY = framebufferManager_->UseBufferedRendering();
// We need correct viewport values in gstate_c already.
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(),
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
vpAndScissor);
}
int maxIndex = indexGen.MaxIndex();
int vertexCount = indexGen.VertexCount();
@@ -574,6 +584,12 @@ void DrawEngineGLES::DoFlush() {
#endif
SoftwareTransform swTransform(params);
const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset);
const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale * (params.flippedY ? 1.0 : -1.0f), gstate_c.vpDepthScale);
const bool invertedY = gstate_c.vpHeight * (params.flippedY ? 1.0 : -1.0f) < 0;
swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, invertedY, trans, scale);
swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
if (result.action == SW_NOT_READY)
swTransform.DetectOffsetTexture(maxIndex);
+7 -1
View File
@@ -33,6 +33,7 @@
#include "Common/GPU/Shader.h"
#include "Common/GPU/thin3d.h"
#include "Common/GPU/OpenGL/GLRenderManager.h"
#include "Common/System/Display.h"
#include "Common/Log.h"
#include "Common/File/FileUtil.h"
@@ -84,7 +85,10 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs,
std::vector<GLRProgram::Semantic> semantics;
semantics.push_back({ ATTR_POSITION, "position" });
semantics.push_back({ ATTR_TEXCOORD, "texcoord" });
semantics.push_back({ ATTR_NORMAL, "normal" });
if (useHWTransform_)
semantics.push_back({ ATTR_NORMAL, "normal" });
else
semantics.push_back({ ATTR_NORMAL, "fog" });
semantics.push_back({ ATTR_W1, "w1" });
semantics.push_back({ ATTR_W2, "w2" });
semantics.push_back({ ATTR_COLOR0, "color0" });
@@ -124,6 +128,7 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs,
queries.push_back({ &u_depthRange, "u_depthRange" });
queries.push_back({ &u_cullRangeMin, "u_cullRangeMin" });
queries.push_back({ &u_cullRangeMax, "u_cullRangeMax" });
queries.push_back({ &u_rotation, "u_rotation" });
#ifdef USE_BONE_ARRAY
queries.push_back({ &u_bone, "u_bone" });
@@ -360,6 +365,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
ScaleProjMatrix(flippedMatrix, useBufferedRendering);
render_->SetUniformM4x4(&u_proj, flippedMatrix.m);
render_->SetUniformF1(&u_rotation, (float)g_display_rotation);
}
if (dirty & DIRTY_PROJTHROUGHMATRIX)
{
+1
View File
@@ -60,6 +60,7 @@ public:
int u_depthRange; // x,y = viewport xscale/xcenter. z,w=clipping minz/maxz (?)
int u_cullRangeMin;
int u_cullRangeMax;
int u_rotation;
#ifdef USE_BONE_ARRAY
int u_bone; // array, size is numBones
+1
View File
@@ -2259,6 +2259,7 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) {
v.x = ((gstate.imm_vscx & 0xFFFFFF) - offsetX) / 16.0f;
v.y = ((gstate.imm_vscy & 0xFFFFFF) - offsetY) / 16.0f;
v.z = gstate.imm_vscz & 0xFFFF;
v.posw = 1.0f;
v.u = getFloat24(gstate.imm_vtcs);
v.v = getFloat24(gstate.imm_vtct);
v.w = getFloat24(gstate.imm_vtcq);
+2 -1
View File
@@ -43,7 +43,7 @@ enum {
struct TransformedVertex {
union {
struct {
float x, y, z, fog; // in case of morph, preblend during decode
float x, y, z, posw; // in case of morph, preblend during decode
};
float pos[4];
};
@@ -53,6 +53,7 @@ struct TransformedVertex {
};
float uv[3];
};
float fog;
union {
u8 color0[4]; // prelit
u32 color0_32;
+11 -2
View File
@@ -909,17 +909,26 @@ void DrawEngineVulkan::DoFlush() {
params.allowClear = framebufferManager_->UseBufferedRendering();
params.allowSeparateAlphaClear = false;
params.provokeFlatFirst = true;
params.flippedY = true;
// We need to update the viewport early because it's checked for flipping in SoftwareTransform.
// We don't have a "DrawStateEarly" in vulkan, so...
// TODO: Probably should eventually refactor this and feed the vp size into SoftwareTransform directly (Unknown's idea).
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
gstate_c.vpWidth = gstate.getViewportXScale() * 2.0f;
gstate_c.vpHeight = gstate.getViewportYScale() * 2.0f;
ViewportAndScissor vpAndScissor;
ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(),
framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),
framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),
vpAndScissor);
}
int maxIndex = indexGen.MaxIndex();
SoftwareTransform swTransform(params);
const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f);
const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale);
swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
if (result.action == SW_NOT_READY) {
swTransform.DetectOffsetTexture(maxIndex);
+11 -7
View File
@@ -115,15 +115,18 @@ static int SetupVertexAttribs(VkVertexInputAttributeDescription attrs[], const D
return count;
}
static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[], bool needsUV, bool needsColor1) {
static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[], bool needsUV, bool needsColor1, bool needsFog) {
int count = 0;
VertexAttribSetup(&attrs[count++], DEC_FLOAT_4, 0, PspAttributeLocation::POSITION);
VertexAttribSetup(&attrs[count++], DEC_FLOAT_4, offsetof(TransformedVertex, pos), PspAttributeLocation::POSITION);
if (needsUV) {
VertexAttribSetup(&attrs[count++], DEC_FLOAT_3, 16, PspAttributeLocation::TEXCOORD);
VertexAttribSetup(&attrs[count++], DEC_FLOAT_3, offsetof(TransformedVertex, uv), PspAttributeLocation::TEXCOORD);
}
VertexAttribSetup(&attrs[count++], DEC_U8_4, 28, PspAttributeLocation::COLOR0);
VertexAttribSetup(&attrs[count++], DEC_U8_4, offsetof(TransformedVertex, color0), PspAttributeLocation::COLOR0);
if (needsColor1) {
VertexAttribSetup(&attrs[count++], DEC_U8_4, 32, PspAttributeLocation::COLOR1);
VertexAttribSetup(&attrs[count++], DEC_U8_4, offsetof(TransformedVertex, color1), PspAttributeLocation::COLOR1);
}
if (needsFog) {
VertexAttribSetup(&attrs[count++], DEC_FLOAT_1, offsetof(TransformedVertex, fog), PspAttributeLocation::NORMAL);
}
return count;
}
@@ -276,8 +279,9 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
} else {
bool needsUV = vs->GetID().Bit(VS_BIT_DO_TEXTURE);
bool needsColor1 = vs->GetID().Bit(VS_BIT_LMODE);
attributeCount = SetupVertexAttribsPretransformed(attrs, needsUV, needsColor1);
vertexStride = 36;
bool needsFog = vs->GetID().Bit(VS_BIT_ENABLE_FOG);
attributeCount = SetupVertexAttribsPretransformed(attrs, needsUV, needsColor1, needsFog);
vertexStride = (int)sizeof(TransformedVertex);
}
VkVertexInputBindingDescription ibd{};