VideoBackends: Scale bounding box rectangle in the pixel shader

This commit is contained in:
Stenzek 2019-03-20 22:14:38 +10:00
parent 20999db93c
commit 16294acd2a
5 changed files with 59 additions and 145 deletions

View File

@ -324,40 +324,11 @@ void Renderer::UnbindTexture(const AbstractTexture* texture)
u16 Renderer::BBoxRead(int index) u16 Renderer::BBoxRead(int index)
{ {
// Here we get the min/max value of the truncated position of the upscaled framebuffer. return static_cast<u16>(BBox::Get(index));
// So we have to correct them to the unscaled EFB sizes.
int value = BBox::Get(index);
if (index < 2)
{
// left/right
value = value * EFB_WIDTH / m_target_width;
}
else
{
// up/down
value = value * EFB_HEIGHT / m_target_height;
}
if (index & 1)
value++; // fix max values to describe the outer border
return value;
} }
void Renderer::BBoxWrite(int index, u16 _value) void Renderer::BBoxWrite(int index, u16 value)
{ {
int value = _value; // u16 isn't enough to multiply by the efb width
if (index & 1)
value--;
if (index < 2)
{
value = value * m_target_width / EFB_WIDTH;
}
else
{
value = value * m_target_height / EFB_HEIGHT;
}
BBox::Set(index, value); BBox::Set(index, value);
} }

View File

@ -837,49 +837,30 @@ void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc)
u16 Renderer::BBoxRead(int index) u16 Renderer::BBoxRead(int index)
{ {
int swapped_index = index; // swap 2 and 3 for top/bottom
if (index >= 2) if (index >= 2)
swapped_index ^= 1; // swap 2 and 3 for top/bottom index ^= 1;
// Here we get the min/max value of the truncated position of the upscaled and swapped int value = BoundingBox::Get(index);
// framebuffer. if (index >= 2)
// So we have to correct them to the unscaled EFB sizes.
int value = BoundingBox::Get(swapped_index);
if (index < 2)
{
// left/right
value = value * EFB_WIDTH / m_target_width;
}
else
{ {
// up/down -- we have to swap up and down // up/down -- we have to swap up and down
value = value * EFB_HEIGHT / m_target_height; value = EFB_HEIGHT - value;
value = EFB_HEIGHT - value - 1;
} }
if (index & 1)
value++; // fix max values to describe the outer border
return value; return static_cast<u16>(value);
} }
void Renderer::BBoxWrite(int index, u16 _value) void Renderer::BBoxWrite(int index, u16 value)
{ {
int value = _value; // u16 isn't enough to multiply by the efb width s32 swapped_value = value;
if (index & 1) if (index >= 2)
value--;
if (index < 2)
{
value = value * m_target_width / EFB_WIDTH;
}
else
{ {
index ^= 1; // swap 2 and 3 for top/bottom index ^= 1; // swap 2 and 3 for top/bottom
value = EFB_HEIGHT - value - 1; swapped_value = EFB_HEIGHT - swapped_value;
value = value * m_target_height / EFB_HEIGHT;
} }
BoundingBox::Set(index, value); BoundingBox::Set(index, swapped_value);
} }
void Renderer::SetViewport(float x, float y, float width, float height, float near_depth, void Renderer::SetViewport(float x, float y, float width, float height, float near_depth,

View File

@ -131,49 +131,12 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline)
u16 Renderer::BBoxRead(int index) u16 Renderer::BBoxRead(int index)
{ {
s32 value = m_bounding_box->Get(static_cast<size_t>(index)); return static_cast<u16>(m_bounding_box->Get(index));
// Here we get the min/max value of the truncated position of the upscaled framebuffer.
// So we have to correct them to the unscaled EFB sizes.
if (index < 2)
{
// left/right
value = value * EFB_WIDTH / m_target_width;
}
else
{
// up/down
value = value * EFB_HEIGHT / m_target_height;
}
// fix max values to describe the outer border
if (index & 1)
value++;
return static_cast<u16>(value);
} }
void Renderer::BBoxWrite(int index, u16 value) void Renderer::BBoxWrite(int index, u16 value)
{ {
s32 scaled_value = static_cast<s32>(value); m_bounding_box->Set(index, value);
// fix max values to describe the outer border
if (index & 1)
scaled_value--;
// scale to internal resolution
if (index < 2)
{
// left/right
scaled_value = scaled_value * m_target_width / EFB_WIDTH;
}
else
{
// up/down
scaled_value = scaled_value * m_target_height / EFB_HEIGHT;
}
m_bounding_box->Set(static_cast<size_t>(index), scaled_value);
} }
void Renderer::BBoxFlush() void Renderer::BBoxFlush()

View File

@ -444,16 +444,46 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType ApiType, u32 num_texg
if (bounding_box) if (bounding_box)
{ {
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) out.Write(R"(
{ #ifdef API_D3D
out.Write("SSBO_BINDING(0) buffer BBox {\n" globallycoherent RWBuffer<int> bbox_data : register(u2);
"\tint bbox_left, bbox_right, bbox_top, bbox_bottom;\n" #define atomicMin InterlockedMin
"};\n"); #define atomicMax InterlockedMax
} #define bbox_left bbox_data[0]
else #define bbox_right bbox_data[1]
{ #define bbox_top bbox_data[2]
out.Write("globallycoherent RWBuffer<int> bbox_data : register(u2);\n"); #define bbox_bottom bbox_data[3]
} #else
SSBO_BINDING(0) buffer BBox {
int bbox_left, bbox_right, bbox_top, bbox_bottom;
};
#endif
void UpdateBoundingBox(float2 rawpos) {
// The pixel center in the GameCube GPU is 7/12, not 0.5 (see VertexShaderGen.cpp)
// Adjust for this by unapplying the offset we added in the vertex shader.
const float PIXEL_CENTER_OFFSET = 7.0 / 12.0 - 0.5;
float2 offset = float2(PIXEL_CENTER_OFFSET, -PIXEL_CENTER_OFFSET);
#ifdef API_OPENGL
// OpenGL lower-left origin means that Y goes in the opposite direction.
offset.y = -offset.y;
#endif
// The bounding box register is exclusive of the right coordinate, hence the +1.
int2 pos = iround(rawpos * cefbscale + offset);
int2 pos_offset = pos + int2(1, 1);
if (bbox_left > pos.x)
atomicMin(bbox_left, pos.x);
if (bbox_right < pos_offset.x)
atomicMax(bbox_right, pos_offset.x);
if (bbox_top > pos.y)
atomicMin(bbox_top, pos.y);
if (bbox_bottom < pos_offset.y)
atomicMax(bbox_bottom, pos_offset.y);
}
)");
} }
} }
@ -859,23 +889,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host
WriteBlend(out, uid_data); WriteBlend(out, uid_data);
if (uid_data->bounding_box) if (uid_data->bounding_box)
{ out.Write("\tUpdateBoundingBox(rawpos.xy);\n");
if (ApiType == APIType::D3D)
{
out.Write(
"\tif(bbox_data[0] > int(rawpos.x)) InterlockedMin(bbox_data[0], int(rawpos.x));\n"
"\tif(bbox_data[1] < int(rawpos.x)) InterlockedMax(bbox_data[1], int(rawpos.x));\n"
"\tif(bbox_data[2] > int(rawpos.y)) InterlockedMin(bbox_data[2], int(rawpos.y));\n"
"\tif(bbox_data[3] < int(rawpos.y)) InterlockedMax(bbox_data[3], int(rawpos.y));\n");
}
else
{
out.Write("\tif(bbox_left > int(rawpos.x)) atomicMin(bbox_left, int(rawpos.x));\n"
"\tif(bbox_right < int(rawpos.x)) atomicMax(bbox_right, int(rawpos.x));\n"
"\tif(bbox_top > int(rawpos.y)) atomicMin(bbox_top, int(rawpos.y));\n"
"\tif(bbox_bottom < int(rawpos.y)) atomicMax(bbox_bottom, int(rawpos.y));\n");
}
}
out.Write("}\n"); out.Write("}\n");

View File

@ -1250,24 +1250,9 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
if (bounding_box) if (bounding_box)
{ {
out.Write(" if (bpmem_bounding_box) {\n"); out.Write(" if (bpmem_bounding_box) {\n"
if (ApiType == APIType::D3D) " UpdateBoundingBox(rawpos.xy);\n"
{ " }\n");
out.Write(
" if(bbox_data[0] > int(rawpos.x)) InterlockedMin(bbox_data[0], int(rawpos.x));\n"
" if(bbox_data[1] < int(rawpos.x)) InterlockedMax(bbox_data[1], int(rawpos.x));\n"
" if(bbox_data[2] > int(rawpos.y)) InterlockedMin(bbox_data[2], int(rawpos.y));\n"
" if(bbox_data[3] < int(rawpos.y)) InterlockedMax(bbox_data[3], int(rawpos.y));\n");
}
else
{
out.Write("\tif(bbox_left > int(rawpos.x)) atomicMin(bbox_left, int(rawpos.x));\n"
"\tif(bbox_right < int(rawpos.x)) atomicMax(bbox_right, int(rawpos.x));\n"
"\tif(bbox_top > int(rawpos.y)) atomicMin(bbox_top, int(rawpos.y));\n"
"\tif(bbox_bottom < int(rawpos.y)) atomicMax(bbox_bottom, int(rawpos.y));\n");
}
out.Write(" }\n");
} }
if (use_shader_blend) if (use_shader_blend)