mirror of https://github.com/PCSX2/pcsx2.git
GS: Remove separate GSTextureCaches
This commit is contained in:
parent
8b086a3898
commit
8d6569be95
|
@ -650,7 +650,6 @@ set(pcsx2GSSources
|
|||
GS/Renderers/OpenGL/GSDeviceOGL.cpp
|
||||
GS/Renderers/OpenGL/GSRendererOGL.cpp
|
||||
GS/Renderers/OpenGL/GSShaderOGL.cpp
|
||||
GS/Renderers/OpenGL/GSTextureCacheOGL.cpp
|
||||
GS/Renderers/OpenGL/GSTextureOGL.cpp
|
||||
GS/Window/GSSetting.cpp
|
||||
GS/Window/GSwxDialog.cpp
|
||||
|
@ -721,7 +720,6 @@ set(pcsx2GSHeaders
|
|||
GS/Renderers/OpenGL/GSDeviceOGL.h
|
||||
GS/Renderers/OpenGL/GSRendererOGL.h
|
||||
GS/Renderers/OpenGL/GSShaderOGL.h
|
||||
GS/Renderers/OpenGL/GSTextureCacheOGL.h
|
||||
GS/Renderers/OpenGL/GSTextureOGL.h
|
||||
GS/Renderers/OpenGL/GSUniformBufferOGL.h
|
||||
GS/Window/GSCaptureDlg.h
|
||||
|
@ -796,7 +794,6 @@ if(WIN32)
|
|||
GS/Renderers/DX11/GSDevice11.cpp
|
||||
GS/Renderers/DX11/GSRendererDX11.cpp
|
||||
GS/Renderers/DX11/GSTexture11.cpp
|
||||
GS/Renderers/DX11/GSTextureCache11.cpp
|
||||
GS/Renderers/DX11/GSTextureFX11.cpp
|
||||
GS/Window/GSCaptureDlg.cpp
|
||||
GS/Window/GSDialog.cpp
|
||||
|
@ -806,7 +803,6 @@ if(WIN32)
|
|||
GS/Renderers/DX11/GSDevice11.h
|
||||
GS/Renderers/DX11/GSRendererDX11.h
|
||||
GS/Renderers/DX11/GSTexture11.h
|
||||
GS/Renderers/DX11/GSTextureCache11.h
|
||||
)
|
||||
else(WIN32)
|
||||
list(APPEND pcsx2SPU2Sources
|
||||
|
|
|
@ -261,6 +261,23 @@ GSTexture::Format GSDevice::GetDefaultTextureFormat(GSTexture::Type type)
|
|||
return GSTexture::Format::Color;
|
||||
}
|
||||
|
||||
bool GSDevice::DownloadTextureConvert(GSTexture* src, const GSVector4& sRect, const GSVector2i& dSize, GSTexture::Format format, ShaderConvert ps_shader, GSTexture::GSMap& out_map)
|
||||
{
|
||||
ASSERT(src);
|
||||
ASSERT(format == GSTexture::Format::Color || format == GSTexture::Format::UInt16 || format == GSTexture::Format::UInt32);
|
||||
|
||||
GSTexture* dst = CreateRenderTarget(dSize.x, dSize.y, format);
|
||||
if (!dst)
|
||||
return false;
|
||||
|
||||
GSVector4i dRect(0, 0, dSize.x, dSize.y);
|
||||
StretchRect(src, sRect, dst, GSVector4(dRect), ps_shader);
|
||||
|
||||
bool ret = DownloadTexture(src, dRect, out_map);
|
||||
Recycle(dst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader, bool linear)
|
||||
{
|
||||
StretchRect(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, shader, linear);
|
||||
|
|
|
@ -228,7 +228,16 @@ public:
|
|||
GSTexture* CreateOffscreen(int w, int h, GSTexture::Format format);
|
||||
GSTexture::Format GetDefaultTextureFormat(GSTexture::Type type);
|
||||
|
||||
virtual GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, GSTexture::Format format, ShaderConvert ps_shader = ShaderConvert::COPY) { return NULL; }
|
||||
/// Download the region `rect` of `src` into `out_map`
|
||||
/// `out_map` will be valid a call to `DownloadTextureComplete`
|
||||
virtual bool DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map) { return false; }
|
||||
|
||||
/// Scale the region `sRect` of `src` to the size `dSize` using `ps_shader` and store the result in `out_map`
|
||||
/// `out_map` will be valid a call to `DownloadTextureComplete`
|
||||
virtual bool DownloadTextureConvert(GSTexture* src, const GSVector4& sRect, const GSVector2i& dSize, GSTexture::Format format, ShaderConvert ps_shader, GSTexture::GSMap& out_map);
|
||||
|
||||
/// Must be called to free resources after calling `DownloadTexture` or `DownloadTextureConvert`
|
||||
virtual void DownloadTextureComplete() {}
|
||||
|
||||
virtual void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r) {}
|
||||
virtual void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader = ShaderConvert::COPY, bool linear = true) {}
|
||||
|
|
|
@ -512,18 +512,17 @@ void GSRenderer::VSync(int field)
|
|||
{
|
||||
GSVector2i size = m_capture.GetSize();
|
||||
|
||||
if (GSTexture* offscreen = m_dev->CopyOffscreen(current, GSVector4(0, 0, 1, 1), size.x, size.y, GSTexture::Format::Color))
|
||||
bool res;
|
||||
GSTexture::GSMap m;
|
||||
if (size == current->GetSize())
|
||||
res = m_dev->DownloadTexture(current, GSVector4i(0, 0, size.x, size.y), m);
|
||||
else
|
||||
res = m_dev->DownloadTextureConvert(current, GSVector4(0, 0, 1, 1), size, GSTexture::Format::Color, ShaderConvert::COPY, m);
|
||||
|
||||
if (res)
|
||||
{
|
||||
GSTexture::GSMap m;
|
||||
|
||||
if (offscreen->Map(m))
|
||||
{
|
||||
m_capture.DeliverFrame(m.bits, m.pitch, !m_dev->IsRBSwapped());
|
||||
|
||||
offscreen->Unmap();
|
||||
}
|
||||
|
||||
m_dev->Recycle(offscreen);
|
||||
m_capture.DeliverFrame(m.bits, m.pitch, !m_dev->IsRBSwapped());
|
||||
m_dev->DownloadTextureComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -648,29 +648,24 @@ GSTexture* GSDevice11::FetchSurface(GSTexture::Type type, int w, int h, GSTextur
|
|||
return __super::FetchSurface(type, w, h, format);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice11::CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, GSTexture::Format format, ShaderConvert ps_shader)
|
||||
bool GSDevice11::DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map)
|
||||
{
|
||||
GSTexture* dst = NULL;
|
||||
ASSERT(src);
|
||||
ASSERT(!m_download_tex);
|
||||
m_download_tex.reset(static_cast<GSTexture11*>(CreateOffscreen(rect.width(), rect.height(), src->GetFormat())));
|
||||
if (!m_download_tex)
|
||||
return false;
|
||||
m_ctx->CopyResource(*m_download_tex, *static_cast<GSTexture11*>(src));
|
||||
return m_download_tex->Map(out_map);
|
||||
}
|
||||
|
||||
ASSERT(format == GSTexture::Format::Color || format == GSTexture::Format::UInt16 || format == GSTexture::Format::UInt32);
|
||||
|
||||
if (GSTexture* rt = CreateRenderTarget(w, h, format))
|
||||
void GSDevice11::DownloadTextureComplete()
|
||||
{
|
||||
if (m_download_tex)
|
||||
{
|
||||
GSVector4 dRect(0, 0, w, h);
|
||||
|
||||
StretchRect(src, sRect, rt, dRect, m_convert.ps[static_cast<int>(ps_shader)].get(), NULL);
|
||||
|
||||
dst = CreateOffscreen(w, h, format);
|
||||
|
||||
if (dst)
|
||||
{
|
||||
m_ctx->CopyResource(*(GSTexture11*)dst, *(GSTexture11*)rt);
|
||||
}
|
||||
|
||||
Recycle(rt);
|
||||
m_download_tex->Unmap();
|
||||
Recycle(m_download_tex.release());
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void GSDevice11::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r)
|
||||
|
|
|
@ -513,6 +513,7 @@ private:
|
|||
PSConstantBuffer m_ps_cb_cache;
|
||||
|
||||
std::unique_ptr<GSTexture> m_font;
|
||||
std::unique_ptr<GSTexture11> m_download_tex;
|
||||
|
||||
protected:
|
||||
struct
|
||||
|
@ -542,7 +543,8 @@ public:
|
|||
void ClearDepth(GSTexture* t) final;
|
||||
void ClearStencil(GSTexture* t, u8 c) final;
|
||||
|
||||
GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, GSTexture::Format format, ShaderConvert ps_shader = ShaderConvert::COPY) final;
|
||||
bool DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map) final;
|
||||
void DownloadTextureComplete() final;
|
||||
|
||||
void CloneTexture(GSTexture* src, GSTexture** dest);
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "GSRendererDX11.h"
|
||||
|
||||
GSRendererDX11::GSRendererDX11()
|
||||
: GSRendererHW(new GSTextureCache11(this))
|
||||
{
|
||||
m_sw_blending = theApp.GetConfigI("accurate_blending_unit_d3d11");
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "GSDevice11.h"
|
||||
#include "GS/Renderers/HW/GSRendererHW.h"
|
||||
#include "GSTextureCache11.h"
|
||||
#include "GS/Renderers/HW/GSVertexHW.h"
|
||||
|
||||
class GSRendererDX11 final : public GSRendererHW
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSTextureCache11.h"
|
||||
|
||||
// GSTextureCache11
|
||||
|
||||
GSTextureCache11::GSTextureCache11(GSRenderer* r)
|
||||
: GSTextureCache(r)
|
||||
{
|
||||
}
|
||||
|
||||
void GSTextureCache11::Read(Target* t, const GSVector4i& r)
|
||||
{
|
||||
if (!t->m_dirty.empty() || r.width() == 0 || r.height() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const GIFRegTEX0& TEX0 = t->m_TEX0;
|
||||
|
||||
GSTexture::Format format;
|
||||
ShaderConvert ps_shader;
|
||||
switch (TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMCT32:
|
||||
case PSM_PSMCT24:
|
||||
format = GSTexture::Format::Color;
|
||||
ps_shader = ShaderConvert::COPY;
|
||||
break;
|
||||
|
||||
case PSM_PSMCT16:
|
||||
case PSM_PSMCT16S:
|
||||
format = GSTexture::Format::UInt16;
|
||||
ps_shader = ShaderConvert::RGBA8_TO_16_BITS;
|
||||
break;
|
||||
|
||||
case PSM_PSMZ32:
|
||||
case PSM_PSMZ24:
|
||||
format = GSTexture::Format::UInt32;
|
||||
ps_shader = ShaderConvert::FLOAT32_TO_32_BITS;
|
||||
break;
|
||||
|
||||
case PSM_PSMZ16:
|
||||
case PSM_PSMZ16S:
|
||||
format = GSTexture::Format::UInt16;
|
||||
ps_shader = ShaderConvert::FLOAT32_TO_32_BITS;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// printf("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n", r.left, r.top, r.right, r.bottom, TEX0.TBP0);
|
||||
|
||||
int w = r.width();
|
||||
int h = r.height();
|
||||
|
||||
GSVector4 src = GSVector4(r) * GSVector4(t->m_texture->GetScale()).xyxy() / GSVector4(t->m_texture->GetSize()).xyxy();
|
||||
|
||||
if (GSTexture* offscreen = m_renderer->m_dev->CopyOffscreen(t->m_texture, src, w, h, format, ps_shader))
|
||||
{
|
||||
GSTexture::GSMap m;
|
||||
|
||||
if (offscreen->Map(m))
|
||||
{
|
||||
// TODO: block level write
|
||||
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
switch (TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMCT32:
|
||||
case PSM_PSMZ32:
|
||||
m_renderer->m_mem.WritePixel32(m.bits, m.pitch, off, r);
|
||||
break;
|
||||
case PSM_PSMCT24:
|
||||
case PSM_PSMZ24:
|
||||
m_renderer->m_mem.WritePixel24(m.bits, m.pitch, off, r);
|
||||
break;
|
||||
case PSM_PSMCT16:
|
||||
case PSM_PSMCT16S:
|
||||
case PSM_PSMZ16:
|
||||
case PSM_PSMZ16S:
|
||||
m_renderer->m_mem.WritePixel16(m.bits, m.pitch, off, r);
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
offscreen->Unmap();
|
||||
}
|
||||
|
||||
m_renderer->m_dev->Recycle(offscreen);
|
||||
}
|
||||
}
|
||||
|
||||
void GSTextureCache11::Read(Source* t, const GSVector4i& r)
|
||||
{
|
||||
// FIXME: copy was copyied from openGL. It is unlikely to work.
|
||||
|
||||
const GIFRegTEX0& TEX0 = t->m_TEX0;
|
||||
|
||||
if (GSTexture* offscreen = m_renderer->m_dev->CreateOffscreen(r.width(), r.height(), GSTexture::Format::Color))
|
||||
{
|
||||
m_renderer->m_dev->CopyRect(t->m_texture, offscreen, r);
|
||||
|
||||
GSTexture::GSMap m;
|
||||
GSVector4i r_offscreen(0, 0, r.width(), r.height());
|
||||
|
||||
if (offscreen->Map(m, &r_offscreen))
|
||||
{
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
m_renderer->m_mem.WritePixel32(m.bits, m.pitch, off, r);
|
||||
|
||||
offscreen->Unmap();
|
||||
}
|
||||
|
||||
// FIXME invalidate data
|
||||
m_renderer->m_dev->Recycle(offscreen);
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS/Renderers/HW/GSTextureCache.h"
|
||||
#include "GSDevice11.h"
|
||||
|
||||
class GSTextureCache11 : public GSTextureCache
|
||||
{
|
||||
protected:
|
||||
int Get8bitFormat() { return DXGI_FORMAT_A8_UNORM; }
|
||||
|
||||
void Read(Target* t, const GSVector4i& r);
|
||||
void Read(Source* t, const GSVector4i& r);
|
||||
|
||||
public:
|
||||
GSTextureCache11(GSRenderer* r);
|
||||
};
|
|
@ -19,14 +19,14 @@
|
|||
|
||||
const float GSRendererHW::SSR_UV_TOLERANCE = 1e-3f;
|
||||
|
||||
GSRendererHW::GSRendererHW(GSTextureCache* tc)
|
||||
GSRendererHW::GSRendererHW()
|
||||
: m_width(default_rt_size.x)
|
||||
, m_height(default_rt_size.y)
|
||||
, m_custom_width(1024)
|
||||
, m_custom_height(1024)
|
||||
, m_reset(false)
|
||||
, m_userhacks_ts_half_bottom(-1)
|
||||
, m_tc(tc)
|
||||
, m_tc(new GSTextureCache(this))
|
||||
, m_src(nullptr)
|
||||
, m_userhacks_tcoffset(false)
|
||||
, m_userhacks_tcoffset_x(0)
|
||||
|
|
|
@ -165,7 +165,7 @@ protected:
|
|||
void CustomResolutionScaling();
|
||||
|
||||
public:
|
||||
GSRendererHW(GSTextureCache* tc);
|
||||
GSRendererHW();
|
||||
virtual ~GSRendererHW();
|
||||
|
||||
void SetGameCRC(u32 crc, int options);
|
||||
|
|
|
@ -1655,6 +1655,103 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(const GIFRegTEX0& TEX0, int
|
|||
return t;
|
||||
}
|
||||
|
||||
void GSTextureCache::Read(Target* t, const GSVector4i& r)
|
||||
{
|
||||
if (!t->m_dirty.empty() || r.width() == 0 || r.height() == 0)
|
||||
return;
|
||||
|
||||
const GIFRegTEX0& TEX0 = t->m_TEX0;
|
||||
|
||||
GSTexture::Format fmt;
|
||||
ShaderConvert ps_shader;
|
||||
switch (TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMCT32:
|
||||
case PSM_PSMCT24:
|
||||
fmt = GSTexture::Format::Color;
|
||||
ps_shader = ShaderConvert::COPY;
|
||||
break;
|
||||
|
||||
case PSM_PSMCT16:
|
||||
case PSM_PSMCT16S:
|
||||
fmt = GSTexture::Format::UInt16;
|
||||
ps_shader = ShaderConvert::RGBA8_TO_16_BITS;
|
||||
break;
|
||||
|
||||
case PSM_PSMZ32:
|
||||
case PSM_PSMZ24:
|
||||
fmt = GSTexture::Format::UInt32;
|
||||
ps_shader = ShaderConvert::FLOAT32_TO_32_BITS;
|
||||
break;
|
||||
|
||||
case PSM_PSMZ16:
|
||||
case PSM_PSMZ16S:
|
||||
fmt = GSTexture::Format::UInt16;
|
||||
ps_shader = ShaderConvert::FLOAT32_TO_32_BITS;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// Yes lots of logging, but I'm not confident with this code
|
||||
GL_PUSH("Texture Cache Read. Format(0x%x)", TEX0.PSM);
|
||||
|
||||
GL_PERF("TC: Read Back Target: %d (0x%x)[fmt: 0x%x]. Size %dx%d",
|
||||
t->m_texture->GetID(), TEX0.TBP0, TEX0.PSM, r.width(), r.height());
|
||||
|
||||
GSVector4 src = GSVector4(r) * GSVector4(t->m_texture->GetScale()).xyxy() / GSVector4(t->m_texture->GetSize()).xyxy();
|
||||
|
||||
bool res;
|
||||
GSTexture::GSMap m;
|
||||
|
||||
if (t->m_texture->GetScale() == GSVector2(1, 1) && ps_shader == ShaderConvert::COPY)
|
||||
res = m_renderer->m_dev->DownloadTexture(t->m_texture, r, m);
|
||||
else
|
||||
res = m_renderer->m_dev->DownloadTextureConvert(t->m_texture, src, GSVector2i(r.width(), r.height()), fmt, ps_shader, m);
|
||||
|
||||
if (res)
|
||||
{
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
switch (TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMCT32:
|
||||
case PSM_PSMZ32:
|
||||
m_renderer->m_mem.WritePixel32(m.bits, m.pitch, off, r);
|
||||
break;
|
||||
case PSM_PSMCT24:
|
||||
case PSM_PSMZ24:
|
||||
m_renderer->m_mem.WritePixel24(m.bits, m.pitch, off, r);
|
||||
break;
|
||||
case PSM_PSMCT16:
|
||||
case PSM_PSMCT16S:
|
||||
case PSM_PSMZ16:
|
||||
case PSM_PSMZ16S:
|
||||
m_renderer->m_mem.WritePixel16(m.bits, m.pitch, off, r);
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
m_renderer->m_dev->DownloadTextureComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void GSTextureCache::Read(Source* t, const GSVector4i& r)
|
||||
{
|
||||
const GIFRegTEX0& TEX0 = t->m_TEX0;
|
||||
|
||||
GSTexture::GSMap m;
|
||||
if (m_renderer->m_dev->DownloadTexture(t->m_texture, r, m))
|
||||
{
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
m_renderer->m_mem.WritePixel32(m.bits, m.pitch, off, r);
|
||||
m_renderer->m_dev->DownloadTextureComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void GSTextureCache::PrintMemoryUsage()
|
||||
{
|
||||
#ifdef ENABLE_OGL_DEBUG
|
||||
|
|
|
@ -226,19 +226,17 @@ protected:
|
|||
u8 m_texture_inside_rt_cache_size = 255;
|
||||
std::vector<TexInsideRtCacheEntry> m_texture_inside_rt_cache;
|
||||
|
||||
virtual Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t = NULL, bool half_right = false, int x_offset = 0, int y_offset = 0);
|
||||
virtual Target* CreateTarget(const GIFRegTEX0& TEX0, int w, int h, int type);
|
||||
|
||||
virtual int Get8bitFormat() = 0;
|
||||
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t = NULL, bool half_right = false, int x_offset = 0, int y_offset = 0);
|
||||
Target* CreateTarget(const GIFRegTEX0& TEX0, int w, int h, int type);
|
||||
|
||||
// TODO: virtual void Write(Source* s, const GSVector4i& r) = 0;
|
||||
// TODO: virtual void Write(Target* t, const GSVector4i& r) = 0;
|
||||
|
||||
public:
|
||||
GSTextureCache(GSRenderer* r);
|
||||
virtual ~GSTextureCache();
|
||||
virtual void Read(Target* t, const GSVector4i& r) = 0;
|
||||
virtual void Read(Source* t, const GSVector4i& r) = 0;
|
||||
~GSTextureCache();
|
||||
void Read(Target* t, const GSVector4i& r);
|
||||
void Read(Source* t, const GSVector4i& r);
|
||||
void RemoveAll();
|
||||
void RemovePartial();
|
||||
|
||||
|
|
|
@ -1271,23 +1271,14 @@ void GSDeviceOGL::SelfShaderTest()
|
|||
SelfShaderTestPrint(test, nb_shader);
|
||||
}
|
||||
|
||||
// blit a texture into an offscreen buffer
|
||||
GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, GSTexture::Format format, ShaderConvert ps_shader)
|
||||
bool GSDeviceOGL::DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map)
|
||||
{
|
||||
ASSERT(src);
|
||||
ASSERT(format == GSTexture::Format::Color || format == GSTexture::Format::UInt16 || format == GSTexture::Format::UInt32);
|
||||
|
||||
GSTexture* dst = CreateOffscreen(w, h, format);
|
||||
GSTextureOGL* srcgl = static_cast<GSTextureOGL*>(src);
|
||||
|
||||
const GSVector4 dRect(0, 0, w, h);
|
||||
|
||||
// StretchRect will read an old target. However, the memory cache might contains
|
||||
// invalid data (for example due to SW blending).
|
||||
glTextureBarrier();
|
||||
|
||||
StretchRect(src, sRect, dst, dRect, m_convert.ps[(int)ps_shader]);
|
||||
|
||||
return dst;
|
||||
out_map = srcgl->Read(rect, m_download_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy a sub part of texture (same as below but force a conversion)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "GSUniformBufferOGL.h"
|
||||
#include "GSShaderOGL.h"
|
||||
#include "GLState.h"
|
||||
#include "GS/GS.h"
|
||||
|
||||
#ifdef ENABLE_OGL_DEBUG_MEM_BW
|
||||
extern u64 g_real_texture_upload_byte;
|
||||
|
@ -558,6 +559,7 @@ private:
|
|||
MiscConstantBuffer m_misc_cb_cache;
|
||||
|
||||
std::unique_ptr<GSTexture> m_font;
|
||||
AlignedBuffer<u8, 32> m_download_buffer;
|
||||
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int w, int h, GSTexture::Format format) final;
|
||||
GSTexture* FetchSurface(GSTexture::Type type, int w, int h, GSTexture::Format format) final;
|
||||
|
@ -605,7 +607,7 @@ public:
|
|||
void InitPrimDateTexture(GSTexture* rt, const GSVector4i& area);
|
||||
void RecycleDateTexture();
|
||||
|
||||
GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sRect, int w, int h, GSTexture::Format format, ShaderConvert ps_shader = ShaderConvert::COPY) final;
|
||||
bool DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map) final;
|
||||
|
||||
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r) final;
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
|
||||
GSRendererOGL::GSRendererOGL()
|
||||
: GSRendererHW(new GSTextureCacheOGL(this))
|
||||
{
|
||||
m_sw_blending = theApp.GetConfigI("accurate_blending_unit");
|
||||
if (theApp.GetConfigB("UserHacks"))
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "GSDeviceOGL.h"
|
||||
#include "GS/Renderers/HW/GSRendererHW.h"
|
||||
#include "GSTextureCacheOGL.h"
|
||||
#include "GS/Renderers/HW/GSVertexHW.h"
|
||||
|
||||
class GSRendererOGL final : public GSRendererHW
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSTextureCacheOGL.h"
|
||||
|
||||
GSTextureCacheOGL::GSTextureCacheOGL(GSRenderer* r)
|
||||
: GSTextureCache(r)
|
||||
{
|
||||
}
|
||||
|
||||
void GSTextureCacheOGL::Read(Target* t, const GSVector4i& r)
|
||||
{
|
||||
if (!t->m_dirty.empty() || r.width() == 0 || r.height() == 0)
|
||||
return;
|
||||
|
||||
const GIFRegTEX0& TEX0 = t->m_TEX0;
|
||||
|
||||
GSTexture::Format fmt;
|
||||
ShaderConvert ps_shader;
|
||||
switch (TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMCT32:
|
||||
case PSM_PSMCT24:
|
||||
fmt = GSTexture::Format::Color;
|
||||
ps_shader = ShaderConvert::COPY;
|
||||
break;
|
||||
|
||||
case PSM_PSMCT16:
|
||||
case PSM_PSMCT16S:
|
||||
fmt = GSTexture::Format::UInt16;
|
||||
ps_shader = ShaderConvert::RGBA8_TO_16_BITS;
|
||||
break;
|
||||
|
||||
case PSM_PSMZ32:
|
||||
case PSM_PSMZ24:
|
||||
fmt = GSTexture::Format::UInt32;
|
||||
ps_shader = ShaderConvert::FLOAT32_TO_32_BITS;
|
||||
break;
|
||||
|
||||
case PSM_PSMZ16:
|
||||
case PSM_PSMZ16S:
|
||||
fmt = GSTexture::Format::UInt16;
|
||||
ps_shader = ShaderConvert::FLOAT32_TO_32_BITS;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Yes lots of logging, but I'm not confident with this code
|
||||
GL_PUSH("Texture Cache Read. Format(0x%x)", TEX0.PSM);
|
||||
|
||||
GL_PERF("TC: Read Back Target: %d (0x%x)[fmt: 0x%x]. Size %dx%d",
|
||||
t->m_texture->GetID(), TEX0.TBP0, TEX0.PSM, r.width(), r.height());
|
||||
|
||||
GSVector4 src = GSVector4(r) * GSVector4(t->m_texture->GetScale()).xyxy() / GSVector4(t->m_texture->GetSize()).xyxy();
|
||||
|
||||
if (GSTexture* offscreen = m_renderer->m_dev->CopyOffscreen(t->m_texture, src, r.width(), r.height(), fmt, ps_shader))
|
||||
{
|
||||
GSTexture::GSMap m;
|
||||
GSVector4i r_offscreen(0, 0, r.width(), r.height());
|
||||
|
||||
if (offscreen->Map(m, &r_offscreen))
|
||||
{
|
||||
// TODO: block level write
|
||||
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
switch (TEX0.PSM)
|
||||
{
|
||||
case PSM_PSMCT32:
|
||||
case PSM_PSMZ32:
|
||||
m_renderer->m_mem.WritePixel32(m.bits, m.pitch, off, r);
|
||||
break;
|
||||
case PSM_PSMCT24:
|
||||
case PSM_PSMZ24:
|
||||
m_renderer->m_mem.WritePixel24(m.bits, m.pitch, off, r);
|
||||
break;
|
||||
case PSM_PSMCT16:
|
||||
case PSM_PSMCT16S:
|
||||
case PSM_PSMZ16:
|
||||
case PSM_PSMZ16S:
|
||||
m_renderer->m_mem.WritePixel16(m.bits, m.pitch, off, r);
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
offscreen->Unmap();
|
||||
}
|
||||
|
||||
// FIXME invalidate data
|
||||
m_renderer->m_dev->Recycle(offscreen);
|
||||
}
|
||||
}
|
||||
|
||||
void GSTextureCacheOGL::Read(Source* t, const GSVector4i& r)
|
||||
{
|
||||
const GIFRegTEX0& TEX0 = t->m_TEX0;
|
||||
|
||||
// FIXME Create a get function to avoid the useless copy
|
||||
// Note: With openGL 4.5 you can use glGetTextureSubImage
|
||||
|
||||
if (GSTexture* offscreen = m_renderer->m_dev->CreateOffscreen(r.width(), r.height(), GSTexture::Format::Color))
|
||||
{
|
||||
m_renderer->m_dev->CopyRect(t->m_texture, offscreen, r);
|
||||
|
||||
GSTexture::GSMap m;
|
||||
GSVector4i r_offscreen(0, 0, r.width(), r.height());
|
||||
|
||||
if (offscreen->Map(m, &r_offscreen))
|
||||
{
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
m_renderer->m_mem.WritePixel32(m.bits, m.pitch, off, r);
|
||||
|
||||
offscreen->Unmap();
|
||||
}
|
||||
|
||||
// FIXME invalidate data
|
||||
m_renderer->m_dev->Recycle(offscreen);
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS/Renderers/HW/GSTextureCache.h"
|
||||
#include "GSDeviceOGL.h"
|
||||
|
||||
class GSTextureCacheOGL final : public GSTextureCache
|
||||
{
|
||||
protected:
|
||||
int Get8bitFormat() { return GL_R8; }
|
||||
|
||||
void Read(Target* t, const GSVector4i& r);
|
||||
void Read(Source* t, const GSVector4i& r);
|
||||
|
||||
public:
|
||||
GSTextureCacheOGL(GSRenderer* r);
|
||||
};
|
|
@ -162,7 +162,7 @@ namespace PboPool
|
|||
} // namespace PboPool
|
||||
|
||||
GSTextureOGL::GSTextureOGL(Type type, int w, int h, Format format, GLuint fbo_read, bool mipmap)
|
||||
: m_clean(false), m_generate_mipmap(true), m_local_buffer(nullptr), m_r_x(0), m_r_y(0), m_r_w(0), m_r_h(0), m_layer(0)
|
||||
: m_clean(false), m_generate_mipmap(true), m_r_x(0), m_r_y(0), m_r_w(0), m_r_h(0), m_layer(0)
|
||||
{
|
||||
// OpenGL didn't like dimensions of size 0
|
||||
m_size.x = std::max(1, w);
|
||||
|
@ -248,10 +248,6 @@ GSTextureOGL::GSTextureOGL(Type type, int w, int h, Format format, GLuint fbo_re
|
|||
{
|
||||
case Type::Backbuffer:
|
||||
return; // backbuffer isn't a real texture
|
||||
case Type::Offscreen:
|
||||
// Offscreen is only used to read color. So it only requires 4B by pixel
|
||||
m_local_buffer = (u8*)_aligned_malloc(m_size.x * m_size.y * 4, 32);
|
||||
break;
|
||||
case Type::Texture:
|
||||
// Only 32 bits input texture will be supported for mipmap
|
||||
m_max_layer = mipmap && m_format == Format::Color ? (int)log2(std::max(w, h)) : 1;
|
||||
|
@ -351,9 +347,6 @@ GSTextureOGL::~GSTextureOGL()
|
|||
glDeleteTextures(1, &m_texture_id);
|
||||
|
||||
GLState::available_vram += m_mem_usage;
|
||||
|
||||
if (m_local_buffer)
|
||||
_aligned_free(m_local_buffer);
|
||||
}
|
||||
|
||||
void GSTextureOGL::Clear(const void* data)
|
||||
|
@ -450,36 +443,7 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
|
|||
u32 row_byte = r.width() << m_int_shift;
|
||||
m.pitch = row_byte;
|
||||
|
||||
if (m_type == Type::Offscreen)
|
||||
{
|
||||
// The fastest way will be to use a PBO to read the data asynchronously. Unfortunately GSdx
|
||||
// architecture is waiting the data right now.
|
||||
|
||||
#ifdef GL_EXT_TEX_SUB_IMAGE
|
||||
// Maybe it is as good as the code below. I don't know
|
||||
// With openGL 4.5 you can use glGetTextureSubImage
|
||||
|
||||
glGetTextureSubImage(m_texture_id, GL_TEX_LEVEL_0, r.x, r.y, 0, r.width(), r.height(), 1, m_int_format, m_int_type, m_size.x * m_size.y * 4, m_local_buffer);
|
||||
#else
|
||||
|
||||
// Bind the texture to the read framebuffer to avoid any disturbance
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0);
|
||||
|
||||
// In case a target is 16 bits (GT4)
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1u << m_int_shift);
|
||||
|
||||
glReadPixels(r.x, r.y, r.width(), r.height(), m_int_format, m_int_type, m_local_buffer);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
|
||||
#endif
|
||||
|
||||
m.bits = m_local_buffer;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (m_type == Type::Texture || m_type == Type::RenderTarget)
|
||||
if (m_type == Type::Texture || m_type == Type::RenderTarget)
|
||||
{
|
||||
GL_PUSH_("Upload Texture %d", m_texture_id); // POP is in Unmap
|
||||
|
||||
|
@ -573,6 +537,36 @@ void GSTextureOGL::CommitPages(const GSVector2i& region, bool commit)
|
|||
GLState::available_vram -= m_mem_usage;
|
||||
}
|
||||
|
||||
GSTexture::GSMap GSTextureOGL::Read(const GSVector4i& r, AlignedBuffer<u8, 32>& buffer)
|
||||
{
|
||||
GSMap m;
|
||||
m.pitch = r.width() << m_int_shift;
|
||||
buffer.MakeRoomFor(m.pitch * r.height());
|
||||
m.bits = buffer.GetPtr();
|
||||
|
||||
// The fastest way will be to use a PBO to read the data asynchronously. Unfortunately GSdx
|
||||
// architecture is waiting the data right now.
|
||||
#if 0
|
||||
// Maybe it is as good as the code below. I don't know
|
||||
// With openGL 4.5 you can use glGetTextureSubImage
|
||||
|
||||
glGetTextureSubImage(m_texture_id, GL_TEX_LEVEL_0, r.x, r.y, 0, r.width(), r.height(), 1, m_int_format, m_int_type, m_size.x * m_size.y * 4, m.bits);
|
||||
#else
|
||||
// Bind the texture to the read framebuffer to avoid any disturbance
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0);
|
||||
|
||||
// In case a target is 16 bits (GT4)
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1u << m_int_shift);
|
||||
|
||||
glReadPixels(r.x, r.y, r.width(), r.height(), m_int_format, m_int_type, m.bits);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
#endif
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
bool GSTextureOGL::Save(const std::string& fn)
|
||||
{
|
||||
// Collect the texture data
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "GS/Renderers/Common/GSTexture.h"
|
||||
#include "GS/GSGL.h"
|
||||
#include "common/AlignedMalloc.h"
|
||||
|
||||
namespace PboPool
|
||||
{
|
||||
|
@ -41,7 +42,6 @@ private:
|
|||
bool m_clean;
|
||||
bool m_generate_mipmap;
|
||||
|
||||
u8* m_local_buffer;
|
||||
// Avoid alignment constrain
|
||||
//GSVector4i m_r;
|
||||
int m_r_x;
|
||||
|
@ -69,6 +69,7 @@ public:
|
|||
void GenerateMipmap() final;
|
||||
bool Save(const std::string& fn) final;
|
||||
|
||||
GSMap Read(const GSVector4i& r, AlignedBuffer<u8, 32>& buffer);
|
||||
bool IsBackbuffer() { return (m_type == Type::Backbuffer); }
|
||||
bool IsDss() { return (m_type == Type::DepthStencil || m_type == Type::SparseDepthStencil); }
|
||||
|
||||
|
|
|
@ -499,8 +499,6 @@
|
|||
<ClCompile Include="GS\Renderers\DX11\GSTexture11.cpp" />
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GSTextureOGL.cpp" />
|
||||
<ClCompile Include="GS\Renderers\HW\GSTextureCache.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX11\GSTextureCache11.cpp" />
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GSTextureCacheOGL.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSTextureCacheSW.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX11\GSTextureFX11.cpp" />
|
||||
<ClCompile Include="GS\Renderers\Null\GSTextureNull.cpp" />
|
||||
|
@ -864,8 +862,6 @@
|
|||
<ClInclude Include="GS\Renderers\DX11\GSTexture11.h" />
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GSTextureOGL.h" />
|
||||
<ClInclude Include="GS\Renderers\HW\GSTextureCache.h" />
|
||||
<ClInclude Include="GS\Renderers\DX11\GSTextureCache11.h" />
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GSTextureCacheOGL.h" />
|
||||
<ClInclude Include="GS\Renderers\SW\GSTextureCacheSW.h" />
|
||||
<ClInclude Include="GS\Renderers\Null\GSTextureNull.h" />
|
||||
<ClInclude Include="GS\Renderers\SW\GSTextureSW.h" />
|
||||
|
|
|
@ -1493,9 +1493,6 @@
|
|||
<ClCompile Include="GS\Renderers\DX11\GSTexture11.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\DX11\GSTextureCache11.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\DX11\GSTextureFX11.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1511,9 +1508,6 @@
|
|||
<ClCompile Include="GS\Renderers\OpenGL\GSShaderOGL.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GSTextureCacheOGL.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GSTextureOGL.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||
</ClCompile>
|
||||
|
@ -2593,9 +2587,6 @@
|
|||
<ClInclude Include="GS\Renderers\DX11\GSTexture11.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\DX11\GSTextureCache11.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GLLoader.h">
|
||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
|
@ -2608,9 +2599,6 @@
|
|||
<ClInclude Include="GS\Renderers\OpenGL\GSShaderOGL.h">
|
||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GSTextureCacheOGL.h">
|
||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GSTextureOGL.h">
|
||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
|
|
Loading…
Reference in New Issue