mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 00:59:44 -06:00
Main change: Implemented EFB pokes in DX9/DX11.
Games affected by this change: Mario Smash Football, Mario Strikers Charged Football, Monster Hunter Tri. Other games possibly affected: Shaun White Snowboarding, Resident Evil Code: Veronica, Baten Kaitos. This implementation will decrease performance if the game uses this feature, but the glitches will be gone. I'll add an option for this in a later commit. EFB pokes are somewhat slow in DX11 right now, speed should be okayish in DX9 though. Other changes: - SOMEWHAT cleaned up the EFB access code in DX9 - Fixed incompatible parameter list of AccessEFB and TVideo_AccessEFB. - Fixed a theoretical bug in ReplaceRGBATexture2D, add support for STAGING textures - Removed unused parameters in various DX9 functions git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6300 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -24,7 +24,7 @@ namespace D3D
|
||||
|
||||
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage)
|
||||
{
|
||||
if (usage == D3D11_USAGE_DYNAMIC)
|
||||
if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
@ -35,7 +35,7 @@ void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned
|
||||
else
|
||||
{
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, map.RowPitch);
|
||||
memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, 4 * pitch);
|
||||
}
|
||||
D3D::context->Unmap(pTexture, level);
|
||||
}
|
||||
|
@ -429,11 +429,13 @@ ID3D11SamplerState* linear_copy_sampler = NULL;
|
||||
ID3D11SamplerState* point_copy_sampler = NULL;
|
||||
ID3D11Buffer* stqvb = NULL;
|
||||
ID3D11Buffer* stsqvb = NULL;
|
||||
ID3D11Buffer* quadvb = NULL;
|
||||
ID3D11Buffer* clearvb = NULL;
|
||||
|
||||
typedef struct { float x,y,z,u,v; } STQVertex;
|
||||
typedef struct { float x,y,z,u,v; } STSQVertex;
|
||||
typedef struct { float x,y,z; u32 col; } ClearVertex;
|
||||
typedef struct { float x,y,z; u32 col; } ColVertex;
|
||||
|
||||
struct
|
||||
{
|
||||
@ -446,6 +448,12 @@ struct
|
||||
float u1, v1, u2, v2;
|
||||
} tex_sub_quad_data;
|
||||
|
||||
struct
|
||||
{
|
||||
float x1, y1, x2, y2;
|
||||
u32 col;
|
||||
} draw_quad_data;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 col;
|
||||
@ -468,6 +476,7 @@ void InitUtils()
|
||||
// cached data used to avoid unnecessarily reloading the vertex buffers
|
||||
memset(&tex_quad_data, 0, sizeof(tex_quad_data));
|
||||
memset(&tex_sub_quad_data, 0, sizeof(tex_sub_quad_data));
|
||||
memset(&draw_quad_data, 0, sizeof(draw_quad_data));
|
||||
memset(&clear_quad_data, 0, sizeof(clear_quad_data));
|
||||
|
||||
STQVertex stqcoords[4] = {
|
||||
@ -480,6 +489,9 @@ void InitUtils()
|
||||
STSQVertex stsqcoords[4];
|
||||
memset(stsqcoords, 0, sizeof(stsqcoords));
|
||||
|
||||
ColVertex colcoords[4];
|
||||
memset(colcoords, 0, sizeof(colcoords));
|
||||
|
||||
ClearVertex cqcoords[4] = {
|
||||
{-1.0f, 1.0f, 0, 0},
|
||||
{ 1.0f, 1.0f, 0, 0},
|
||||
@ -495,6 +507,10 @@ void InitUtils()
|
||||
CHECK(stsqvb!=NULL, "Create vertex buffer of drawShadedTexSubQuad");
|
||||
SetDebugObjectName((ID3D11DeviceChild*)stsqvb, "vertex buffer of drawShadedTexSubQuad");
|
||||
|
||||
quadvb = CreateQuadVertexBuffer(4*sizeof(ColVertex), colcoords);
|
||||
CHECK(quadvb!=NULL, "Create vertex buffer of drawColorQuad");
|
||||
SetDebugObjectName((ID3D11DeviceChild*)quadvb, "vertex buffer of drawColorQuad");
|
||||
|
||||
clearvb = CreateQuadVertexBuffer(4*sizeof(ClearVertex), cqcoords);
|
||||
CHECK(clearvb!=NULL, "Create vertex buffer of drawClearQuad");
|
||||
SetDebugObjectName((ID3D11DeviceChild*)clearvb, "vertex buffer of drawClearQuad");
|
||||
@ -509,6 +525,7 @@ void ShutdownUtils()
|
||||
SAFE_RELEASE(linear_copy_sampler);
|
||||
SAFE_RELEASE(stqvb);
|
||||
SAFE_RELEASE(stsqvb);
|
||||
SAFE_RELEASE(quadvb);
|
||||
SAFE_RELEASE(clearvb);
|
||||
}
|
||||
|
||||
@ -627,6 +644,45 @@ void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture,
|
||||
context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
|
||||
}
|
||||
|
||||
// Fills a certain area of the current render target with the specified color
|
||||
// destination coordinates normalized to (-1;1)
|
||||
void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
if(draw_quad_data.x1 != x1 || draw_quad_data.y1 != y1 ||
|
||||
draw_quad_data.x2 != x2 || draw_quad_data.y2 != y2 ||
|
||||
draw_quad_data.col != Color)
|
||||
{
|
||||
ColVertex coords[4] = {
|
||||
{ x1, y2, 0.f, Color },
|
||||
{ x2, y2, 0.f, Color },
|
||||
{ x1, y1, 0.f, Color },
|
||||
{ x2, y1, 0.f, Color },
|
||||
};
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
context->Map(quadvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
||||
memcpy(map.pData, coords, sizeof(coords));
|
||||
context->Unmap(quadvb, 0);
|
||||
|
||||
draw_quad_data.x1 = x1;
|
||||
draw_quad_data.y1 = y1;
|
||||
draw_quad_data.x2 = x2;
|
||||
draw_quad_data.y2 = y2;
|
||||
draw_quad_data.col = Color;
|
||||
}
|
||||
|
||||
context->VSSetShader(VertexShaderCache::GetClearVertexShader(), NULL, 0);
|
||||
context->PSSetShader(PixelShaderCache::GetClearProgram(), NULL, 0);
|
||||
context->IASetInputLayout(VertexShaderCache::GetClearInputLayout());
|
||||
|
||||
UINT stride = sizeof(ColVertex);
|
||||
UINT offset = 0;
|
||||
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
context->IASetVertexBuffers(0, 1, &quadvb, &stride, &offset);
|
||||
|
||||
context->Draw(4, 0);
|
||||
}
|
||||
|
||||
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout)
|
||||
{
|
||||
if (clear_quad_data.col != Color || clear_quad_data.z != z)
|
||||
@ -657,5 +713,4 @@ void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexS
|
||||
context->Draw(4, 0);
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
@ -80,6 +80,5 @@ namespace D3D
|
||||
ID3D11VertexShader* Vshader,
|
||||
ID3D11InputLayout* layout);
|
||||
void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout);
|
||||
void SaveRenderStates();
|
||||
void RestoreRenderStates();
|
||||
void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2);
|
||||
}
|
||||
|
@ -594,19 +594,19 @@ void Renderer::SetColorMask()
|
||||
D3D::gfxstate->SetRenderTargetWriteMask(color_mask);
|
||||
}
|
||||
|
||||
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
ID3D11Texture2D* read_tex;
|
||||
u32 ret = 0;
|
||||
|
||||
if (!g_ActiveConfig.bEFBAccessEnable)
|
||||
return 0;
|
||||
|
||||
if (type == POKE_Z || type == POKE_COLOR)
|
||||
if (type == POKE_Z)
|
||||
{
|
||||
static bool alert_only_once = true;
|
||||
if (!alert_only_once) return 0;
|
||||
PanicAlert("Poke EFB not implemented");
|
||||
PanicAlert("EFB: Poke Z not implemented (tried to poke z value %#x at (%d,%d))", poke_data, x, y);
|
||||
alert_only_once = false;
|
||||
return 0;
|
||||
}
|
||||
@ -619,12 +619,23 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
efbPixelRc.bottom = y + 1;
|
||||
TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc);
|
||||
|
||||
// Take the mean of the resulting dimensions; TODO: check whether this causes any bugs compared to taking the average color of the target area
|
||||
// Take the mean of the resulting dimensions; TODO: Don't use the center pixel, compute the average color instead
|
||||
D3D11_RECT RectToLock;
|
||||
RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2;
|
||||
RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
||||
RectToLock.right = RectToLock.left + 1;
|
||||
RectToLock.bottom = RectToLock.top + 1;
|
||||
if(type == PEEK_COLOR || type == PEEK_Z)
|
||||
{
|
||||
RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2;
|
||||
RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
||||
RectToLock.right = RectToLock.left + 1;
|
||||
RectToLock.bottom = RectToLock.top + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
RectToLock.left = targetPixelRc.left;
|
||||
RectToLock.right = targetPixelRc.right;
|
||||
RectToLock.top = targetPixelRc.top;
|
||||
RectToLock.bottom = targetPixelRc.bottom;
|
||||
}
|
||||
|
||||
if (type == PEEK_Z)
|
||||
{
|
||||
ResetAPIState(); // Reset any game specific settings
|
||||
@ -651,40 +662,59 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
D3D::context->CopySubresourceRegion(read_tex, 0, 0, 0, 0, g_framebufferManager.GetEFBDepthReadTexture()->GetTex(), 0, &box);
|
||||
|
||||
RestoreAPIState(); // restore game state
|
||||
|
||||
// read the data from system memory
|
||||
D3D::context->Map(read_tex, 0, D3D11_MAP_READ, 0, &map);
|
||||
|
||||
float val = *(float*)map.pData;
|
||||
u32 ret = ((u32)(val * 0xffffff));
|
||||
D3D::context->Unmap(read_tex, 0);
|
||||
|
||||
// TODO: in RE0 this value is often off by one in Video_DX9 (where this code is derived from), which causes lighting to disappear
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
else if (type == PEEK_COLOR)
|
||||
{
|
||||
// we can directly copy to system memory here
|
||||
read_tex = g_framebufferManager.GetEFBColorStagingBuffer();
|
||||
D3D11_BOX box = CD3D11_BOX(RectToLock.left, RectToLock.top, 0, RectToLock.right, RectToLock.bottom, 1);
|
||||
D3D::context->CopySubresourceRegion(read_tex, 0, 0, 0, 0, g_framebufferManager.GetEFBColorTexture()->GetTex(), 0, &box);
|
||||
|
||||
// read the data from system memory
|
||||
D3D::context->Map(read_tex, 0, D3D11_MAP_READ, 0, &map);
|
||||
u32 ret = *(u32*)map.pData;
|
||||
D3D::context->Unmap(read_tex, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// read the data from system memory
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
D3D::context->Map(read_tex, 0, D3D11_MAP_READ, 0, &map);
|
||||
|
||||
switch(type)
|
||||
else //if(type == POKE_COLOR)
|
||||
{
|
||||
case PEEK_Z:
|
||||
// TODO: Speed this up by batching pokes?
|
||||
// If we're only writing one pixel (native resolution), we can directly copy the data into the target. TODO: Check if this is faster than drawing quads
|
||||
u32 rgbaColor = (poke_data & 0xFF00FF00) | ((poke_data >> 16) & 0xFF) | ((poke_data << 16) & 0xFF0000);
|
||||
if(RectToLock.right <= RectToLock.left + 1 && RectToLock.bottom <= RectToLock.top + 1)
|
||||
{
|
||||
float val = *(float*)map.pData;
|
||||
ret = ((u32)(val * 0xffffff));
|
||||
break;
|
||||
D3D::context->Map(g_framebufferManager.GetEFBColorStagingBuffer(), 0, D3D11_MAP_WRITE, 0, &map);
|
||||
*(u32*)map.pData = rgbaColor;
|
||||
D3D::context->Unmap(g_framebufferManager.GetEFBColorStagingBuffer(), 0);
|
||||
|
||||
D3D11_BOX box = CD3D11_BOX(0, 0, 0, 1, 1, 1);
|
||||
D3D::context->CopySubresourceRegion(g_framebufferManager.GetEFBColorTexture()->GetTex(), 0, RectToLock.left, RectToLock.top, 0, g_framebufferManager.GetEFBColorStagingBuffer(), 0, &box);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetAPIState(); // Reset any game specific settings
|
||||
|
||||
case PEEK_COLOR:
|
||||
ret = *(u32*)map.pData;
|
||||
break;
|
||||
D3D::context->OMSetRenderTargets(1, &g_framebufferManager.GetEFBColorTexture()->GetRTV(), NULL);
|
||||
D3D::drawColorQuad(rgbaColor, (float)RectToLock.left * 2.f / (float)Renderer::GetFullTargetWidth() - 1.f,
|
||||
- (float)RectToLock.top * 2.f / (float)Renderer::GetFullTargetHeight() + 1.f,
|
||||
(float)RectToLock.right * 2.f / (float)Renderer::GetFullTargetWidth() - 1.f,
|
||||
- (float)RectToLock.bottom * 2.f / (float)Renderer::GetFullTargetHeight() + 1.f);
|
||||
|
||||
default:
|
||||
// TODO: Implement POKE_Z and POKE_COLOR
|
||||
break;
|
||||
RestoreAPIState();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
D3D::context->Unmap(read_tex, 0);
|
||||
// TODO: in RE0 this value is often off by one in Video_DX9 (where this code is derived from), which causes lighting to disappear
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Called from VertexShaderManager
|
||||
|
@ -378,7 +378,7 @@ void VideoFifo_CheckEFBAccess()
|
||||
{
|
||||
if (Common::AtomicLoadAcquire(s_efbAccessRequested))
|
||||
{
|
||||
s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y);
|
||||
s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y, s_accessEFBArgs.Data);
|
||||
|
||||
Common::AtomicStoreRelease(s_efbAccessRequested, FALSE);
|
||||
}
|
||||
|
Reference in New Issue
Block a user