diff --git a/Source/Core/VideoCommon/Src/Render.h b/Source/Core/VideoCommon/Src/Render.h index 146c10e9bc..b7149a02d3 100644 --- a/Source/Core/VideoCommon/Src/Render.h +++ b/Source/Core/VideoCommon/Src/Render.h @@ -89,7 +89,7 @@ public: static void DrawDebugText(); static void SetScreenshot(const char *filename); static void FlipImageData(u8 *data, int w, int h); - static bool SaveRenderTarget(const char *filename, int w, int h, int YOffset = 0); + static bool SaveRenderTarget(const char *filename, TargetRectangle back_rc); static void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp index 79e5d59b61..605091bb72 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp @@ -117,7 +117,7 @@ void InitPP(int adapter, int f, int aa_mode, D3DPRESENT_PARAMETERS *pp) pp->EnableAutoDepthStencil = FALSE; pp->AutoDepthStencilFormat = D3DFMT_UNKNOWN; } - pp->BackBufferFormat = D3DFMT_A8R8G8B8; + pp->BackBufferFormat = D3DFMT_X8R8G8B8; if (aa_mode >= (int)adapters[adapter].aa_levels.size()) aa_mode = 0; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index 7cab18f0d0..ad8ccfc62e 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -357,7 +357,7 @@ bool Renderer::Init() D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x0, 1.0f, 0); D3D::BeginFrame(); D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, true); - D3D::dev->CreateOffscreenPlainSurface(s_backbuffer_width,s_backbuffer_height, FBManager.GetEFBColorRTSurfaceFormat(), D3DPOOL_SYSTEMMEM, &ScreenShootMEMSurface, NULL ); + D3D::dev->CreateOffscreenPlainSurface(s_backbuffer_width,s_backbuffer_height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &ScreenShootMEMSurface, NULL ); return true; } @@ -494,7 +494,7 @@ void formatBufferDump(const char *in, char *out, int w, int h, int p) memcpy(out, line, 3); out += 3; line += 4; - } + } } } @@ -531,6 +531,9 @@ void CheckForResize() D3D::Reset(); s_backbuffer_width = D3D::GetBackBufferWidth(); s_backbuffer_height = D3D::GetBackBufferHeight(); + if(ScreenShootMEMSurface) + ScreenShootMEMSurface->Release(); + D3D::dev->CreateOffscreenPlainSurface(s_backbuffer_width,s_backbuffer_height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &ScreenShootMEMSurface, NULL ); WindowResized = true; } } @@ -1082,28 +1085,26 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons if(s_bScreenshot) { s_criticalScreenshot.Enter(); - // create a R8G8B8 surface for the screenshot (no alpha channel) - // otherwise funky screenshots get saved - LPDIRECT3DSURFACE9 screenshot_surface; - if (D3D_OK == D3D::dev->CreateOffscreenPlainSurface(s_backbuffer_width, s_backbuffer_height, D3DFMT_R8G8B8, D3DPOOL_SCRATCH, &screenshot_surface, NULL)) + HRESULT hr = D3D::dev->GetRenderTargetData(D3D::GetBackBufferSurface(),ScreenShootMEMSurface);//, NULL, dst_rect.AsRECT(), D3D::GetBackBufferSurface(), NULL, dst_rect.AsRECT(), D3DX_FILTER_NONE, 0); + if(FAILED(hr)) { - D3DXLoadSurfaceFromSurface(screenshot_surface, NULL, NULL, D3D::GetBackBufferSurface(), NULL, NULL, D3DX_DEFAULT, 0); - D3DXSaveSurfaceToFileA(s_sScreenshotName, D3DXIFF_PNG, screenshot_surface, NULL, NULL); - screenshot_surface->Release(); + PanicAlert("Error dumping surface data."); + } + hr = D3DXSaveSurfaceToFileA(s_sScreenshotName, D3DXIFF_PNG, ScreenShootMEMSurface, NULL, dst_rect.AsRECT()); + if(FAILED(hr)) + { + PanicAlert("Error saving screen."); } - else - PanicAlert("Failed to create surface for screenshot!"); - s_bScreenshot = false; s_criticalScreenshot.Leave(); } if (g_ActiveConfig.bDumpFrames) { - D3D::dev->GetRenderTargetData(D3D::GetBackBufferSurface(), ScreenShootMEMSurface); + HRESULT hr = D3D::dev->GetRenderTargetData(D3D::GetBackBufferSurface(),ScreenShootMEMSurface); if (!s_LastFrameDumped) { - s_recordWidth = s_backbuffer_width; - s_recordHeight = s_backbuffer_height; + s_recordWidth = dst_rect.GetWidth(); + s_recordHeight = dst_rect.GetHeight(); s_AVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), s_recordWidth, s_recordHeight); if (!s_AVIDumping) { @@ -1119,7 +1120,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons if (s_AVIDumping) { D3DLOCKED_RECT rect; - if (SUCCEEDED(ScreenShootMEMSurface->LockRect(&rect, NULL, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY))) + if (SUCCEEDED(ScreenShootMEMSurface->LockRect(&rect, dst_rect.AsRECT(), D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY))) { char* data = (char*)malloc(3 * s_recordWidth * s_recordHeight); formatBufferDump((const char*)rect.pBits, data, s_recordWidth, s_recordHeight, rect.Pitch); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp index c095114b54..aafcd34864 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp @@ -111,14 +111,7 @@ void TextureCache::MakeRangeDynamic(u32 start_address, u32 size) int rangePosition = iter->second.IntersectsMemoryRange(start_address, size); if ( rangePosition == 0) { - if(iter->second.addr != start_address) - { - if(!iter->second.isRenderTarget) - { - iter->second.isDinamic = true; - } - iter->second.hash = 0; - } + iter->second.hash = 0; } else { @@ -223,11 +216,15 @@ TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, if (!g_ActiveConfig.bSafeTextureCache) { - if(entry.isRenderTarget) + if(entry.isRenderTarget || entry.isDinamic) { if(!g_ActiveConfig.bCopyEFBToTexture && g_ActiveConfig.bVerifyTextureModificationsByCPU) { hash_value = TexDecoder_GetHash64(ptr,TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, tex_format),g_ActiveConfig.iSafeTextureCache_ColorSamples); + if ((tex_format == GX_TF_C4) || (tex_format == GX_TF_C8) || (tex_format == GX_TF_C14X2)) + { + hash_value ^= TexDecoder_GetHash64(&texMem[tlutaddr], TexDecoder_GetPaletteSize(tex_format),g_ActiveConfig.iSafeTextureCache_ColorSamples); + } } else { @@ -239,9 +236,17 @@ TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, hash_value = ((u32 *)ptr)[0]; } } - - - if ((entry.isRenderTarget && hash_value == entry.hash && address == entry.addr) + else + { + if(entry.isRenderTarget || entry.isDinamic) + { + if(g_ActiveConfig.bCopyEFBToTexture || !g_ActiveConfig.bVerifyTextureModificationsByCPU) + { + hash_value = 0; + } + } + } + if (((entry.isRenderTarget || entry.isDinamic) && hash_value == entry.hash && address == entry.addr) || ((address == entry.addr) && (hash_value == entry.hash) && FullFormat == entry.fmt/* && entry.MipLevels == maxlevel*/)) @@ -255,7 +260,7 @@ TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, // Let's reload the new texture data into the same texture, // instead of destroying it and having to create a new one. // Might speed up movie playback very, very slightly. - TextureIsDinamic = true; + TextureIsDinamic = (entry.isRenderTarget || entry.isDinamic) && !g_ActiveConfig.bCopyEFBToTexture; if (!entry.isRenderTarget && ((!entry.isDinamic && width == entry.w && height==entry.h && FullFormat == entry.fmt /* && entry.MipLevels < maxlevel*/) @@ -329,12 +334,12 @@ TextureCache::TCacheEntry *TextureCache::Load(int stage, u32 address, int width, } entry.oldpixel = ((u32 *)ptr)[0]; - if (g_ActiveConfig.bSafeTextureCache) + if (g_ActiveConfig.bSafeTextureCache || entry.isDinamic) entry.hash = hash_value; else { entry.hash = (u32)(((double)rand() / RAND_MAX) * 0xFFFFFFFF); - ((u32 *)ptr)[0] = entry.hash; + ((u32 *)ptr)[0] = entry.hash; } entry.addr = address; @@ -464,7 +469,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, boo { TCacheEntry entry; entry.addr = address; - entry.isRenderTarget = !TextureIsDinamic; + entry.isRenderTarget = true; entry.hash = 0; entry.frameCount = frameCount; entry.w = tex_w; @@ -484,7 +489,6 @@ void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, boo // We have to run a pixel shader, for color conversion. Renderer::ResetAPIState(); // reset any game specific settings - if(!TextureIsDinamic || g_ActiveConfig.bCopyEFBToTexture) { @@ -662,7 +666,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, boo if(!g_ActiveConfig.bCopyEFBToTexture) { - TextureConverter::EncodeToRamFromTexture( + textures[address].hash = TextureConverter::EncodeToRamFromTexture( address, read_texture, Renderer::GetFullTargetWidth(), @@ -676,22 +680,6 @@ void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, boo copyfmt, bScaleByHalf, source_rect); - - u8 *ptr = g_VideoInitialize.pGetMemoryPointer(address); - int bsw = TexDecoder_GetBlockWidthInTexels(copyfmt) - 1; - int bsh = TexDecoder_GetBlockHeightInTexels(copyfmt) - 1; - int expandedWidth = (tex_w + bsw) & (~bsw); - int expandedHeight = (tex_h + bsh) & (~bsh); - u32 textureSize = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, copyfmt); - MakeRangeDynamic(address,textureSize); - if(g_ActiveConfig.bVerifyTextureModificationsByCPU) - { - textures[address].hash = TexDecoder_GetHash64(ptr,textureSize,g_ActiveConfig.iSafeTextureCache_ColorSamples); - } - else - { - textures[address].hash = 0; - } } D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp index de45fe79f1..b4b32ecf05 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp @@ -389,7 +389,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf Renderer::RestoreAPIState(); } -void EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) +u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) { u32 format = copyfmt; @@ -407,7 +407,7 @@ void EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 So LPDIRECT3DPIXELSHADER9 texconv_shader = GetOrCreateEncodingShader(format); if (!texconv_shader) - return; + return 0; u8 *dest_ptr = Memory_GetPtr(address); @@ -448,6 +448,13 @@ void EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 So int readStride = (expandedWidth * cacheBytes) / TexDecoder_GetBlockWidthInTexels(format); EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight,readStride, true, bScaleByHalf > 0); + TextureCache::MakeRangeDynamic(address,size_in_bytes); + u64 Hashvalue = 0; + if(g_ActiveConfig.bVerifyTextureModificationsByCPU) + { + Hashvalue = TexDecoder_GetHash64(dest_ptr,size_in_bytes,g_ActiveConfig.iSafeTextureCache_ColorSamples); + } + return Hashvalue; } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.h b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.h index 09c9de3f46..185832833f 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.h @@ -40,7 +40,7 @@ void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourc void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture); -void EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); +u64 EncodeToRamFromTexture(u32 address,LPDIRECT3DTEXTURE9 source_texture,u32 SourceW, u32 SourceH,float MValueX,float MValueY,float Xstride, float Ystride , bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index d8acd73370..4d7ae6f412 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -114,8 +114,6 @@ static int m_CustomHeight; static int m_FrameBufferWidth; static int m_FrameBufferHeight; -static GLuint s_tempScreenshotFramebuffer = 0; - static unsigned int s_XFB_width; static unsigned int s_XFB_height; @@ -485,9 +483,6 @@ void Renderer::Shutdown(void) cgDestroyContext(g_cgcontext); g_cgcontext = 0; } - if(s_tempScreenshotFramebuffer) - glDeleteFramebuffersEXT(1, &s_tempScreenshotFramebuffer); - s_tempScreenshotFramebuffer = 0; g_framebufferManager.Shutdown(); @@ -1031,41 +1026,25 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons // Save screenshot if (s_bScreenshot) { - if (!s_tempScreenshotFramebuffer) - glGenFramebuffersEXT(1, &s_tempScreenshotFramebuffer); - - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_tempScreenshotFramebuffer); - glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, xfbSource->texture, 0); - s_criticalScreenshot.Enter(); // Save screenshot - SaveRenderTarget(s_sScreenshotName.c_str(), xfbSource->sourceRc.GetWidth(), xfbSource->sourceRc.GetHeight()); + SaveRenderTarget(s_sScreenshotName.c_str(), back_rc); // Reset settings s_sScreenshotName = ""; s_bScreenshot = false; - s_criticalScreenshot.Leave(); - - glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, g_framebufferManager.GetEFBFramebuffer()); + s_criticalScreenshot.Leave(); } // Frame dumps are handled a little differently in Windows #ifdef _WIN32 if (g_ActiveConfig.bDumpFrames) { - if (!s_tempScreenshotFramebuffer) - glGenFramebuffersEXT(1, &s_tempScreenshotFramebuffer); - - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_tempScreenshotFramebuffer); - glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, xfbSource->texture, 0); - s_criticalScreenshot.Enter(); - int w = xfbSource->sourceRc.GetWidth(); - int h = xfbSource->sourceRc.GetHeight(); - + int w = back_rc.GetWidth(); + int h = back_rc.GetHeight(); u8 *data = (u8 *) malloc(3 * w * h); glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, Renderer::GetTargetHeight() - h, w, h, GL_BGR, GL_UNSIGNED_BYTE, data); + glReadPixels(back_rc.left, back_rc.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data); if (glGetError() == GL_NO_ERROR && w > 0 && h > 0) { if (!s_bLastFrameDumped) @@ -1089,10 +1068,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons NOTICE_LOG(VIDEO, "Error reading framebuffer"); } free(data); - s_criticalScreenshot.Leave(); - - glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, g_framebufferManager.GetEFBFramebuffer()); + s_criticalScreenshot.Leave(); } else { @@ -1108,11 +1084,11 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons if (g_ActiveConfig.bDumpFrames) { s_criticalScreenshot.Enter(); char movie_file_name[255]; - int w = OpenGL_GetBackbufferWidth(); - int h = OpenGL_GetBackbufferHeight(); + int w = back_rc.GetWidth(); + int h = back_rc.GetHeight(); u8 *data = (u8 *) malloc(3 * w * h); glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, Renderer::GetTargetHeight() - h, w, h, GL_RGB, GL_UNSIGNED_BYTE, data); + glReadPixels(back_rc.left, back_rc.bottom, w, h, GL_BGR, GL_UNSIGNED_BYTE, data); if (glGetError() == GL_NO_ERROR) { if (!s_bLastFrameDumped) { sprintf(movie_file_name, "%sframedump.raw", File::GetUserPath(D_DUMPFRAMES_IDX)); @@ -1509,12 +1485,28 @@ THREAD_RETURN TakeScreenshot(void *pArgs) } #endif -bool Renderer::SaveRenderTarget(const char *filename, int W, int H, int YOffset) +void Renderer::FlipImageData(u8 *data, int w, int h) { + // Flip image upside down. Damn OpenGL. + for (int y = 0; y < h / 2; y++) + { + for(int x = 0; x < w; x++) + { + std::swap(data[(y * w + x) * 3], data[((h - 1 - y) * w + x) * 3]); + std::swap(data[(y * w + x) * 3 + 1], data[((h - 1 - y) * w + x) * 3 + 1]); + std::swap(data[(y * w + x) * 3 + 2], data[((h - 1 - y) * w + x) * 3 + 2]); + } + } +} + +bool Renderer::SaveRenderTarget(const char *filename, TargetRectangle back_rc) +{ + u32 W = back_rc.GetWidth(); + u32 H = back_rc.GetHeight(); u8 *data = (u8 *)malloc(3 * W * H); glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, Renderer::GetTargetHeight() - H + YOffset, W, H, GL_RGB, GL_UNSIGNED_BYTE, data); + glReadPixels(back_rc.left, back_rc.bottom, W, H, GL_RGB, GL_UNSIGNED_BYTE, data); // Show failure message if (glGetError() != GL_NO_ERROR) @@ -1558,19 +1550,7 @@ bool Renderer::SaveRenderTarget(const char *filename, int W, int H, int YOffset) } -void Renderer::FlipImageData(u8 *data, int w, int h) -{ - // Flip image upside down. Damn OpenGL. - for (int y = 0; y < h / 2; y++) - { - for(int x = 0; x < w; x++) - { - std::swap(data[(y * w + x) * 3], data[((h - 1 - y) * w + x) * 3]); - std::swap(data[(y * w + x) * 3 + 1], data[((h - 1 - y) * w + x) * 3 + 1]); - std::swap(data[(y * w + x) * 3 + 2], data[((h - 1 - y) * w + x) * 3 + 2]); - } - } -} + // Called from VertexShaderManager void UpdateViewport() diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp index 1ef2451d29..e145ac0ac8 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp @@ -360,7 +360,12 @@ void Flush() { char str[128]; sprintf(str, "%starg%.3d.tga", File::GetUserPath(D_DUMPFRAMES_IDX), g_ActiveConfig.iSaveTargetId); - Renderer::SaveRenderTarget(str, Renderer::GetTargetWidth(), Renderer::GetTargetHeight()); + TargetRectangle tr; + tr.left = 0; + tr.right = Renderer::GetTargetWidth(); + tr.top = 0; + tr.bottom = Renderer::GetTargetHeight(); + Renderer::SaveRenderTarget(str, tr); } #endif g_Config.iSaveTargetId++;