GS: Remove exceptions

This commit is contained in:
Stenzek 2023-06-28 23:05:53 +10:00 committed by Connor McLaughlin
parent 81236209db
commit a889acb332
17 changed files with 395 additions and 561 deletions

View File

@ -341,54 +341,26 @@ void GSclose()
} }
void GSreset(bool hardware_reset) void GSreset(bool hardware_reset)
{
try
{ {
g_gs_renderer->Reset(hardware_reset); g_gs_renderer->Reset(hardware_reset);
} }
catch (GSRecoverableError)
{
}
}
void GSgifSoftReset(u32 mask) void GSgifSoftReset(u32 mask)
{
try
{ {
g_gs_renderer->SoftReset(mask); g_gs_renderer->SoftReset(mask);
} }
catch (GSRecoverableError)
{
}
}
void GSwriteCSR(u32 csr) void GSwriteCSR(u32 csr)
{
try
{ {
g_gs_renderer->WriteCSR(csr); g_gs_renderer->WriteCSR(csr);
} }
catch (GSRecoverableError)
{
}
}
void GSInitAndReadFIFO(u8* mem, u32 size) void GSInitAndReadFIFO(u8* mem, u32 size)
{ {
GL_PERF("Init and read FIFO %u qwc", size); GL_PERF("Init and read FIFO %u qwc", size);
try
{
g_gs_renderer->InitReadFIFO(mem, size); g_gs_renderer->InitReadFIFO(mem, size);
g_gs_renderer->ReadFIFO(mem, size); g_gs_renderer->ReadFIFO(mem, size);
} }
catch (GSRecoverableError)
{
}
catch (const std::bad_alloc&)
{
fprintf(stderr, "GS: Memory allocation error\n");
}
}
void GSReadLocalMemoryUnsync(u8* mem, u32 qwc, u64 BITBLITBUF, u64 TRXPOS, u64 TRXREG) void GSReadLocalMemoryUnsync(u8* mem, u32 qwc, u64 BITBLITBUF, u64 TRXPOS, u64 TRXREG)
{ {
@ -396,67 +368,31 @@ void GSReadLocalMemoryUnsync(u8* mem, u32 qwc, u64 BITBLITBUF, u64 TRXPOS, u64 T
} }
void GSgifTransfer(const u8* mem, u32 size) void GSgifTransfer(const u8* mem, u32 size)
{
try
{ {
g_gs_renderer->Transfer<3>(mem, size); g_gs_renderer->Transfer<3>(mem, size);
} }
catch (GSRecoverableError)
{
}
}
void GSgifTransfer1(u8* mem, u32 addr) void GSgifTransfer1(u8* mem, u32 addr)
{
try
{ {
g_gs_renderer->Transfer<0>(const_cast<u8*>(mem) + addr, (0x4000 - addr) / 16); g_gs_renderer->Transfer<0>(const_cast<u8*>(mem) + addr, (0x4000 - addr) / 16);
} }
catch (GSRecoverableError)
{
}
}
void GSgifTransfer2(u8* mem, u32 size) void GSgifTransfer2(u8* mem, u32 size)
{
try
{ {
g_gs_renderer->Transfer<1>(const_cast<u8*>(mem), size); g_gs_renderer->Transfer<1>(const_cast<u8*>(mem), size);
} }
catch (GSRecoverableError)
{
}
}
void GSgifTransfer3(u8* mem, u32 size) void GSgifTransfer3(u8* mem, u32 size)
{
try
{ {
g_gs_renderer->Transfer<2>(const_cast<u8*>(mem), size); g_gs_renderer->Transfer<2>(const_cast<u8*>(mem), size);
} }
catch (GSRecoverableError)
{
}
}
void GSvsync(u32 field, bool registers_written) void GSvsync(u32 field, bool registers_written)
{
try
{ {
g_gs_renderer->VSync(field, registers_written, g_gs_renderer->IsIdleFrame()); g_gs_renderer->VSync(field, registers_written, g_gs_renderer->IsIdleFrame());
} }
catch (GSRecoverableError)
{
}
catch (const std::bad_alloc&)
{
fprintf(stderr, "GS: Memory allocation error\n");
}
}
int GSfreeze(FreezeAction mode, freezeData* data) int GSfreeze(FreezeAction mode, freezeData* data)
{
try
{ {
if (mode == FreezeAction::Save) if (mode == FreezeAction::Save)
{ {
@ -466,7 +402,7 @@ int GSfreeze(FreezeAction mode, freezeData* data)
{ {
return g_gs_renderer->Freeze(data, true); return g_gs_renderer->Freeze(data, true);
} }
else if (mode == FreezeAction::Load) else // if (mode == FreezeAction::Load)
{ {
// Since Defrost doesn't do a hardware reset (since it would be clearing // Since Defrost doesn't do a hardware reset (since it would be clearing
// local memory just before it's overwritten), we have to manually wipe // local memory just before it's overwritten), we have to manually wipe
@ -475,12 +411,6 @@ int GSfreeze(FreezeAction mode, freezeData* data)
return g_gs_renderer->Defrost(data); return g_gs_renderer->Defrost(data);
} }
} }
catch (GSRecoverableError)
{
}
return 0;
}
void GSQueueSnapshot(const std::string& path, u32 gsdump_frames) void GSQueueSnapshot(const std::string& path, u32 gsdump_frames)
{ {

View File

@ -119,13 +119,6 @@ bool GSSaveSnapshotToMemory(u32 window_width, u32 window_height, bool apply_aspe
u32* width, u32* height, std::vector<u32>* pixels); u32* width, u32* height, std::vector<u32>* pixels);
void GSJoinSnapshotThreads(); void GSJoinSnapshotThreads();
struct GSError
{
};
struct GSRecoverableError : GSError
{
};
namespace Host namespace Host
{ {
/// Called when the GS is creating a render device. /// Called when the GS is creating a render device.

View File

@ -30,7 +30,7 @@ GSClut::GSClut(GSLocalMemory* mem)
// 1k + 1k for mirrored area simulating wrapping memory // 1k + 1k for mirrored area simulating wrapping memory
m_clut = static_cast<u16*>(_aligned_malloc(CLUT_ALLOC_SIZE, VECTOR_ALIGNMENT)); m_clut = static_cast<u16*>(_aligned_malloc(CLUT_ALLOC_SIZE, VECTOR_ALIGNMENT));
if (!m_clut) if (!m_clut)
throw std::bad_alloc(); pxFailRel("Failed to allocate CLUT storage.");
m_buff32 = reinterpret_cast<u32*>(reinterpret_cast<u8*>(m_clut) + 2048); // 1k m_buff32 = reinterpret_cast<u32*>(reinterpret_cast<u8*>(m_clut) + 2048); // 1k
m_buff64 = reinterpret_cast<u64*>(reinterpret_cast<u8*>(m_clut) + 4096); // 2k m_buff64 = reinterpret_cast<u64*>(reinterpret_cast<u8*>(m_clut) + 4096); // 2k

View File

@ -65,7 +65,7 @@ GSLocalMemory::GSLocalMemory()
{ {
m_vm8 = (u8*)GSAllocateWrappedMemory(m_vmsize, 4); m_vm8 = (u8*)GSAllocateWrappedMemory(m_vmsize, 4);
if (!m_vm8) if (!m_vm8)
throw std::bad_alloc(); pxFailRel("Failed to allocate GS memory storage.");
memset(m_vm8, 0, m_vmsize); memset(m_vm8, 0, m_vmsize);

View File

@ -269,8 +269,8 @@ void GSDumpLzma::Initialize()
if (ret != LZMA_OK) if (ret != LZMA_OK)
{ {
fprintf(stderr, "Error initializing the decoder! (error code %u)\n", ret); Console.Error("Error initializing the decoder! (error code %u)", ret);
throw "BAD"; // Just exit the program pxFailRel("Failed to initialize LZMA decoder.");
} }
m_buff_size = 1024*1024; m_buff_size = 1024*1024;
@ -301,8 +301,8 @@ void GSDumpLzma::Decompress()
if (ferror(m_fp)) if (ferror(m_fp))
{ {
fprintf(stderr, "Read error: %s\n", strerror(errno)); Console.Error("Read error: %s", strerror(errno));
throw "BAD"; // Just exit the program pxFailRel("LZMA read error.");
} }
} }
@ -310,12 +310,10 @@ void GSDumpLzma::Decompress()
if (ret != LZMA_OK) if (ret != LZMA_OK)
{ {
if (ret == LZMA_STREAM_END) if (ret != LZMA_STREAM_END)
fprintf(stderr, "LZMA decoder finished without error\n\n");
else
{ {
fprintf(stderr, "Decoder error: (error code %u)\n", ret); Console.Error("Decoder error: (error code %u)", ret);
throw "BAD"; // Just exit the program pxFailRel("LZMA decoder error.");
} }
} }
@ -395,16 +393,16 @@ void GSDumpDecompressZst::Decompress()
if (ferror(m_fp)) if (ferror(m_fp))
{ {
fprintf(stderr, "Read error: %s\n", strerror(errno)); Console.Error("Zst read error: %s", strerror(errno));
throw "BAD"; // Just exit the program pxFailRel("Zst read error.");
} }
} }
size_t ret = ZSTD_decompressStream(m_strm, &outbuf, &m_inbuf); size_t ret = ZSTD_decompressStream(m_strm, &outbuf, &m_inbuf);
if (ZSTD_isError(ret)) if (ZSTD_isError(ret))
{ {
fprintf(stderr, "Decoder error: (error code %s)\n", ZSTD_getErrorName(ret)); Console.Error("Decoder error: (error code %s)", ZSTD_getErrorName(ret));
throw "BAD"; // Just exit the program pxFailRel("Zst decoder error.");
} }
} }

View File

@ -58,18 +58,15 @@ namespace GSPng
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
png_infop info_ptr = nullptr; png_infop info_ptr = nullptr;
bool success;
try
{
if (png_ptr == nullptr) if (png_ptr == nullptr)
throw GSRecoverableError(); return false;
info_ptr = png_create_info_struct(png_ptr); info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr) if (info_ptr == nullptr)
throw GSRecoverableError(); return false;
if (setjmp(png_jmpbuf(png_ptr))) if (setjmp(png_jmpbuf(png_ptr)))
throw GSRecoverableError(); return false;
png_init_io(png_ptr, fp); png_init_io(png_ptr, fp);
png_set_compression_level(png_ptr, compression); png_set_compression_level(png_ptr, compression);
@ -91,20 +88,11 @@ namespace GSPng
} }
png_write_end(png_ptr, nullptr); png_write_end(png_ptr, nullptr);
success = true;
}
catch (GSRecoverableError&)
{
fprintf(stderr, "Failed to write image %s\n", file.c_str());
success = false;
}
if (png_ptr) if (png_ptr)
png_destroy_write_struct(&png_ptr, info_ptr ? &info_ptr : nullptr); png_destroy_write_struct(&png_ptr, info_ptr ? &info_ptr : nullptr);
fclose(fp); std::fclose(fp);
return success; return true;
} }
bool Save(GSPng::Format fmt, const std::string& file, const u8* image, int w, int h, int pitch, int compression, bool rb_swapped) bool Save(GSPng::Format fmt, const std::string& file, const u8* image, int w, int h, int pitch, int compression, bool rb_swapped)

View File

@ -1643,24 +1643,11 @@ void GSState::FlushPrim()
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM)); m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM));
try
{
// Skip draw if Z test is enabled, but set to fail all pixels. // Skip draw if Z test is enabled, but set to fail all pixels.
const bool skip_draw = (m_context->TEST.ZTE && m_context->TEST.ZTST == ZTST_NEVER); const bool skip_draw = (m_context->TEST.ZTE && m_context->TEST.ZTST == ZTST_NEVER);
if (!skip_draw) if (!skip_draw)
Draw(); Draw();
}
catch (GSRecoverableError&)
{
// could be an unsupported draw call
}
catch (const std::bad_alloc&)
{
// Texture Out Of Memory
PurgePool();
Console.Error("GS: Memory allocation failure.");
}
g_perfmon.Put(GSPerfMon::Draw, 1); g_perfmon.Put(GSPerfMon::Draw, 1);
g_perfmon.Put(GSPerfMon::Prim, m_index.tail / GSUtil::GetVertexCount(PRIM->PRIM)); g_perfmon.Put(GSPerfMon::Prim, m_index.tail / GSUtil::GetVertexCount(PRIM->PRIM));
@ -2706,8 +2693,7 @@ void GSState::GrowVertexBuffer()
Console.Error("GS: failed to allocate %zu bytes for vertices and %zu for indices.", Console.Error("GS: failed to allocate %zu bytes for vertices and %zu for indices.",
vert_byte_count, idx_byte_count); vert_byte_count, idx_byte_count);
pxFailRel("Memory allocation failed");
throw GSError();
} }
if (m_vertex.buff) if (m_vertex.buff)

View File

@ -306,7 +306,15 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
{ {
t = CreateSurface(type, width, height, levels, format); t = CreateSurface(type, width, height, levels, format);
if (!t) if (!t)
throw std::bad_alloc(); {
Console.Error("GS: Memory allocation failure for %dx%d texture. Purging pool and retrying.", width, height);
PurgePool();
if (!t)
{
Console.Error("GS: Memory allocation failure for %dx%d texture after purging pool.", width, height);
return nullptr;
}
}
} }
} }
@ -607,13 +615,9 @@ bool GSDevice::ResizeRenderTarget(GSTexture** t, int w, int h, bool preserve_con
return true; return true;
} }
GSTexture* new_tex;
try
{
const GSTexture::Format fmt = orig_tex ? orig_tex->GetFormat() : GSTexture::Format::Color; const GSTexture::Format fmt = orig_tex ? orig_tex->GetFormat() : GSTexture::Format::Color;
new_tex = FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, fmt, !preserve_contents, true); GSTexture* new_tex = FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, fmt, !preserve_contents, true);
} if (!new_tex)
catch (std::bad_alloc&)
{ {
Console.WriteLn("%dx%d texture allocation failed in ResizeTexture()", w, h); Console.WriteLn("%dx%d texture allocation failed in ResizeTexture()", w, h);
return false; return false;

View File

@ -228,9 +228,7 @@ private:
void Grow() void Grow()
{ {
if (m_capacity == USHRT_MAX) if (m_capacity == USHRT_MAX)
{ pxFailRel("FastList size maxed out at USHRT_MAX (65535) elements, cannot grow futhermore.");
throw std::runtime_error("FastList size maxed out at USHRT_MAX (65535) elements, cannot grow futhermore.");
}
const u16 new_capacity = m_capacity <= (USHRT_MAX / 2) ? (m_capacity * 2) : USHRT_MAX; const u16 new_capacity = m_capacity <= (USHRT_MAX / 2) ? (m_capacity * 2) : USHRT_MAX;
@ -247,9 +245,7 @@ private:
// Initialize the additional space in the stack // Initialize the additional space in the stack
for (u16 i = m_capacity - 1; i < new_capacity - 1; i++) for (u16 i = m_capacity - 1; i < new_capacity - 1; i++)
{
m_free_indexes_stack[i] = i + 1; m_free_indexes_stack[i] = i + 1;
}
m_capacity = new_capacity; m_capacity = new_capacity;
} }

View File

@ -2212,6 +2212,9 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking) if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
{ {
primid_tex = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::PrimID, false); primid_tex = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::PrimID, false);
if (!primid_tex)
return;
StretchRect(config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(), StretchRect(config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(),
primid_tex, GSVector4(config.drawarea), m_date.primid_init_ps[config.datm].get(), nullptr, false); primid_tex, GSVector4(config.drawarea), m_date.primid_init_ps[config.datm].get(), nullptr, false);
} }
@ -2237,6 +2240,9 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const GSVector4 dRect(config.drawarea); const GSVector4 dRect(config.drawarea);
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy(); const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor); hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor);
if (!hdr_rt)
return;
// Warning: StretchRect must be called before BeginScene otherwise // Warning: StretchRect must be called before BeginScene otherwise
// vertices will be overwritten. Trust me you don't want to do that. // vertices will be overwritten. Trust me you don't want to do that.
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false); StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);

View File

@ -2004,6 +2004,12 @@ void GSRendererHW::Draw()
const bool possible_shuffle = m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0 || IsPossibleChannelShuffle(); const bool possible_shuffle = m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0 || IsPossibleChannelShuffle();
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle) : src = tex_psm.depth ? g_texture_cache->LookupDepthSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle) :
g_texture_cache->LookupSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap >= HWMipmapLevel::Basic || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr, possible_shuffle); g_texture_cache->LookupSource(TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap >= HWMipmapLevel::Basic || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr, possible_shuffle);
if (unlikely(!src))
{
GL_INS("ERROR: Source lookup failed, skipping.");
cleanup_cancelled_draw();
return;
}
} }
// Estimate size based on the scissor rectangle and height cache. // Estimate size based on the scissor rectangle and height cache.
@ -2059,6 +2065,12 @@ void GSRendererHW::Draw()
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, target_scale, GSTextureCache::RenderTarget, true, rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, target_scale, GSTextureCache::RenderTarget, true,
fm, false, force_preload, preload_uploads); fm, false, force_preload, preload_uploads);
if (unlikely(!rt))
{
GL_INS("ERROR: Failed to create FRAME target, skipping.");
cleanup_cancelled_draw();
return;
}
} }
} }
@ -2077,6 +2089,12 @@ void GSRendererHW::Draw()
{ {
ds = g_texture_cache->CreateTarget(ZBUF_TEX0, t_size, target_scale, GSTextureCache::DepthStencil, ds = g_texture_cache->CreateTarget(ZBUF_TEX0, t_size, target_scale, GSTextureCache::DepthStencil,
m_cached_ctx.DepthWrite(), 0, false, force_preload); m_cached_ctx.DepthWrite(), 0, false, force_preload);
if (unlikely(!ds))
{
GL_INS("ERROR: Failed to create ZBUF target, skipping.");
cleanup_cancelled_draw();
return;
}
} }
} }
@ -5168,23 +5186,10 @@ void GSRendererHW::OI_DoubleHalfClear(GSTextureCache::Target*& rt, GSTextureCach
// If some of the channels are masked, we need to keep them. // If some of the channels are masked, we need to keep them.
if (!clear_depth && m_cached_ctx.FRAME.FBMSK != 0) if (!clear_depth && m_cached_ctx.FRAME.FBMSK != 0)
{ {
GSTexture* tex = nullptr;
GSTextureCache::Target* target = clear_depth ? ds : rt; GSTextureCache::Target* target = clear_depth ? ds : rt;
const GSVector2 size = GSVector2(static_cast<float>(target->GetUnscaledWidth()) * target->m_scale, static_cast<float>(target->GetUnscaledHeight()) * target->m_scale); GSTexture* tex = g_gs_device->CreateRenderTarget(target->m_texture->GetWidth(), target->m_texture->GetHeight(), target->m_texture->GetFormat(), false);
pxAssert(!target->m_texture->IsDepthStencil());
try
{
tex = g_gs_device->CreateRenderTarget(size.x, size.y, target->m_texture->GetFormat(), false);
}
catch (const std::bad_alloc&)
{
}
if (!tex) if (!tex)
{
Console.Error("(ResizeTexture) Failed to allocate %dx%d texture", size.x, size.y);
return; return;
}
if (clear_depth) if (clear_depth)
{ {
@ -5240,22 +5245,10 @@ void GSRendererHW::OI_DoubleHalfClear(GSTextureCache::Target*& rt, GSTextureCach
// If some of the channels are masked, we need to keep them. // If some of the channels are masked, we need to keep them.
if (m_cached_ctx.FRAME.FBMSK != 0) if (m_cached_ctx.FRAME.FBMSK != 0)
{ {
GSTexture* tex = nullptr;
GSTextureCache::Target* target = rt; GSTextureCache::Target* target = rt;
const GSVector2 size = GSVector2(static_cast<float>(target->GetUnscaledWidth()) * target->m_scale, static_cast<float>(target->GetUnscaledHeight()) * target->m_scale); GSTexture* tex = g_gs_device->CreateRenderTarget(target->m_texture->GetWidth(), target->m_texture->GetHeight(), target->m_texture->GetFormat(), true);
try
{
tex = g_gs_device->CreateRenderTarget(size.x, size.y, target->m_texture->GetFormat(), true);
}
catch (const std::bad_alloc&)
{
}
if (!tex) if (!tex)
{
Console.Error("(ResizeTexture) Failed to allocate %dx%d texture", size.x, size.y);
return; return;
}
g_gs_device->ClearRenderTarget(tex, color); g_gs_device->ClearRenderTarget(tex, color);

View File

@ -579,7 +579,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0
if (GSConfig.UserHacks_DisableDepthSupport) if (GSConfig.UserHacks_DisableDepthSupport)
{ {
GL_CACHE("LookupDepthSource not supported (0x%x, F:0x%x)", TEX0.TBP0, TEX0.PSM); GL_CACHE("LookupDepthSource not supported (0x%x, F:0x%x)", TEX0.TBP0, TEX0.PSM);
throw GSRecoverableError(); return nullptr;
} }
GL_CACHE("TC: Lookup Depth Source <%d,%d => %d,%d> (0x%x, %s, BW: %u, CBP: 0x%x, TW: %d, TH: %d)", r.x, r.y, r.z, GL_CACHE("TC: Lookup Depth Source <%d,%d => %d,%d> (0x%x, %s, BW: %u, CBP: 0x%x, TW: %d, TH: %d)", r.x, r.y, r.z,
@ -756,7 +756,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
if ((TEX0.TW > 10 && !region.HasX()) || (TEX0.TH > 10 && !region.HasY())) if ((TEX0.TW > 10 && !region.HasX()) || (TEX0.TH > 10 && !region.HasY()))
{ {
GL_CACHE("Invalid TEX0 size %ux%u without region, aborting draw.", TEX0.TW, TEX0.TH); GL_CACHE("Invalid TEX0 size %ux%u without region, aborting draw.", TEX0.TW, TEX0.TH);
throw GSRecoverableError(); return nullptr;
} }
const GSVector2i compare_lod(lod ? *lod : GSVector2i(0, 0)); const GSVector2i compare_lod(lod ? *lod : GSVector2i(0, 0));
@ -1382,7 +1382,10 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
if (dst_match) if (dst_match)
{ {
calcRescale(dst_match); calcRescale(dst_match);
dst = CreateTarget(TEX0, new_size.x, new_size.y, scale, type, clear); dst = Target::Create(TEX0, new_size.x, new_size.y, scale, type, clear);
if (!dst)
return nullptr;
dst->m_32_bits_fmt = dst_match->m_32_bits_fmt; dst->m_32_bits_fmt = dst_match->m_32_bits_fmt;
dst->OffsetHack_modxy = dst_match->OffsetHack_modxy; dst->OffsetHack_modxy = dst_match->OffsetHack_modxy;
@ -1454,7 +1457,7 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe
size.x, size.y, fbmask, bp, TEX0.TBW, psm_str(TEX0.PSM)); size.x, size.y, fbmask, bp, TEX0.TBW, psm_str(TEX0.PSM));
} }
Target* dst = CreateTarget(TEX0, size.x, size.y, scale, type, true); Target* dst = Target::Create(TEX0, size.x, size.y, scale, type, true);
// In theory new textures contain invalidated data. Still in theory a new target // In theory new textures contain invalidated data. Still in theory a new target
// must contains the content of the GS memory. // must contains the content of the GS memory.
// In practice, TC will wrongly invalidate some RT. For example due to write on the alpha // In practice, TC will wrongly invalidate some RT. For example due to write on the alpha
@ -2731,18 +2734,9 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
// If the copies overlap, this is a validation error, so we need to copy to a temporary texture first. // If the copies overlap, this is a validation error, so we need to copy to a temporary texture first.
if ((SBP == DBP) && !(GSVector4i(sx, sy, sx + w, sy + h).rintersect(GSVector4i(dx, dy, dx + w, dy + h))).rempty()) if ((SBP == DBP) && !(GSVector4i(sx, sy, sx + w, sy + h).rintersect(GSVector4i(dx, dy, dx + w, dy + h))).rempty())
{ {
GSTexture* tmp_texture = nullptr; GSTexture* tmp_texture = src->m_texture->IsDepthStencil() ?
const GSVector4i src_size = GSVector4i(src->m_texture->GetSize()).xyxy(); g_gs_device->CreateDepthStencil(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false) :
try g_gs_device->CreateRenderTarget(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false);
{
tmp_texture = src->m_texture->IsDepthStencil() ?
g_gs_device->CreateDepthStencil(src_size.x, src_size.y, src->m_texture->GetFormat(), false) :
g_gs_device->CreateRenderTarget(src_size.x, src_size.y, src->m_texture->GetFormat(), false);
}
catch (const std::bad_alloc&)
{
}
if (!tmp_texture) if (!tmp_texture)
{ {
Console.Error("(HW Move) Failed to allocate temporary %dx%d texture on HW move", w, h); Console.Error("(HW Move) Failed to allocate temporary %dx%d texture on HW move", w, h);
@ -2752,7 +2746,7 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
if(tmp_texture->IsDepthStencil()) if(tmp_texture->IsDepthStencil())
{ {
const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h); const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h);
const GSVector4 tmp_rect = src_rect / GSVector4(src_size); const GSVector4 tmp_rect = src_rect / (GSVector4(tmp_texture->GetSize()).xyxy());
const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h)); const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h));
g_gs_device->StretchRect(src->m_texture, tmp_rect, tmp_texture, src_rect, ShaderConvert::DEPTH_COPY, false); g_gs_device->StretchRect(src->m_texture, tmp_rect, tmp_texture, src_rect, ShaderConvert::DEPTH_COPY, false);
g_gs_device->StretchRect(tmp_texture, tmp_rect, dst->m_texture, dst_rect, ShaderConvert::DEPTH_COPY, false); g_gs_device->StretchRect(tmp_texture, tmp_rect, dst->m_texture, dst_rect, ShaderConvert::DEPTH_COPY, false);
@ -4050,35 +4044,25 @@ void GSTextureCache::AgeHashCache()
} }
} }
GSTextureCache::Target* GSTextureCache::CreateTarget(const GIFRegTEX0& TEX0, int w, int h, float scale, int type, const bool clear) GSTextureCache::Target* GSTextureCache::Target::Create(GIFRegTEX0 TEX0, int w, int h, float scale, int type, bool clear)
{ {
ASSERT(type == RenderTarget || type == DepthStencil); ASSERT(type == RenderTarget || type == DepthStencil);
const int scaled_w = static_cast<int>(std::ceil(static_cast<float>(w) * scale)); const int scaled_w = static_cast<int>(std::ceil(static_cast<float>(w) * scale));
const int scaled_h = static_cast<int>(std::ceil(static_cast<float>(h) * scale)); const int scaled_h = static_cast<int>(std::ceil(static_cast<float>(h) * scale));
GSTexture* texture = (type == RenderTarget) ?
g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear) :
g_gs_device->CreateDepthStencil(scaled_w, scaled_h, GSTexture::Format::DepthStencil, clear);
if (!texture)
return nullptr;
// TODO: This leaks if memory allocation fails. Use a unique_ptr so it gets freed, but these Target* t = new Target(TEX0, type, GSVector2i(w, h), scale, texture);
// exceptions really need to get lost.
std::unique_ptr<Target> t = std::make_unique<Target>(TEX0, type);
t->m_unscaled_size = GSVector2i(w, h);
t->m_scale = scale;
if (type == RenderTarget) g_texture_cache->m_target_memory_usage += t->m_texture->GetMemUsage();
{
t->m_texture = g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear);
t->m_used = true; // FIXME g_texture_cache->m_dst[type].push_front(t);
}
else if (type == DepthStencil)
{
t->m_texture = g_gs_device->CreateDepthStencil(scaled_w, scaled_h, GSTexture::Format::DepthStencil, clear);
}
m_target_memory_usage += t->m_texture->GetMemUsage(); return t;
m_dst[type].push_front(t.get());
return t.release();
} }
GSTexture* GSTextureCache::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size) GSTexture* GSTextureCache::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size)
@ -4646,12 +4630,15 @@ bool GSTextureCache::Source::ClutMatch(const PaletteKey& palette_key)
// GSTextureCache::Target // GSTextureCache::Target
GSTextureCache::Target::Target(const GIFRegTEX0& TEX0, const int type) GSTextureCache::Target::Target(GIFRegTEX0 TEX0, int type, const GSVector2i& unscaled_size, float scale, GSTexture* texture)
: m_type(type) : m_type(type)
, m_used(false) , m_used(type == RenderTarget) // FIXME
, m_valid(GSVector4i::zero()) , m_valid(GSVector4i::zero())
{ {
m_TEX0 = TEX0; m_TEX0 = TEX0;
m_unscaled_size = unscaled_size;
m_scale = scale;
m_texture = texture;
m_32_bits_fmt |= (GSLocalMemory::m_psm[TEX0.PSM].trbpp != 16); m_32_bits_fmt |= (GSLocalMemory::m_psm[TEX0.PSM].trbpp != 16);
} }
@ -4876,19 +4863,9 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca
const int new_height = static_cast<int>(std::ceil(new_unscaled_height) * m_scale); const int new_height = static_cast<int>(std::ceil(new_unscaled_height) * m_scale);
const bool clear = (new_width > width || new_height > height); const bool clear = (new_width > width || new_height > height);
// These exceptions *really* need to get lost. This gets called outside of draws, which just crashes GSTexture* tex = m_texture->IsDepthStencil() ?
// when it tries to propagate the exception back.
GSTexture* tex = nullptr;
try
{
tex = m_texture->IsDepthStencil() ?
g_gs_device->CreateDepthStencil(new_width, new_height, m_texture->GetFormat(), clear) : g_gs_device->CreateDepthStencil(new_width, new_height, m_texture->GetFormat(), clear) :
g_gs_device->CreateRenderTarget(new_width, new_height, m_texture->GetFormat(), clear); g_gs_device->CreateRenderTarget(new_width, new_height, m_texture->GetFormat(), clear);
}
catch (const std::bad_alloc&)
{
}
if (!tex) if (!tex)
{ {
Console.Error("(ResizeTexture) Failed to allocate %dx%d texture from %dx%d texture", new_width, new_height, width, height); Console.Error("(ResizeTexture) Failed to allocate %dx%d texture from %dx%d texture", new_width, new_height, width, height);

View File

@ -227,9 +227,11 @@ public:
int readbacks_since_draw = 0; int readbacks_since_draw = 0;
public: public:
Target(const GIFRegTEX0& TEX0, const int type); Target(GIFRegTEX0 TEX0, int type, const GSVector2i& unscaled_size, float scale, GSTexture* texture);
~Target(); ~Target();
static Target* Create(GIFRegTEX0 TEX0, int w, int h, float scale, int type, bool clear);
void ResizeDrawn(const GSVector4i& rect); void ResizeDrawn(const GSVector4i& rect);
void UpdateDrawn(const GSVector4i& rect, bool can_resize = true); void UpdateDrawn(const GSVector4i& rect, bool can_resize = true);
void ResizeValidity(const GSVector4i& rect); void ResizeValidity(const GSVector4i& rect);
@ -406,7 +408,6 @@ protected:
std::unique_ptr<GSDownloadTexture> m_uint32_download_texture; std::unique_ptr<GSDownloadTexture> m_uint32_download_texture;
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t, bool half_right, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region); Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t, bool half_right, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region);
Target* CreateTarget(const GIFRegTEX0& TEX0, int w, int h, float scale, int type, const bool clear);
/// Expands a target when the block pointer for a display framebuffer is within another target, but the read offset /// Expands a target when the block pointer for a display framebuffer is within another target, but the read offset
/// plus the height is larger than the current size of the target. /// plus the height is larger than the current size of the target.

View File

@ -673,7 +673,7 @@ MRCOwned<id<MTLFunction>> GSDeviceMTL::LoadShader(NSString* name)
{ {
NSString* msg = [NSString stringWithFormat:@"Failed to load shader %@: %@", name, [err localizedDescription]]; NSString* msg = [NSString stringWithFormat:@"Failed to load shader %@: %@", name, [err localizedDescription]];
Console.Error("%s", [msg UTF8String]); Console.Error("%s", [msg UTF8String]);
throw GSRecoverableError(); pxFailRel("Failed to load shader, check the log for more details.");
} }
return fn; return fn;
} }
@ -689,7 +689,7 @@ MRCOwned<id<MTLRenderPipelineState>> GSDeviceMTL::MakePipeline(MTLRenderPipeline
{ {
NSString* msg = [NSString stringWithFormat:@"Failed to create pipeline %@: %@", name, [err localizedDescription]]; NSString* msg = [NSString stringWithFormat:@"Failed to create pipeline %@: %@", name, [err localizedDescription]];
Console.Error("%s", [msg UTF8String]); Console.Error("%s", [msg UTF8String]);
throw GSRecoverableError(); pxFailRel("Failed to create pipeline, check the log for more details.");
} }
return res; return res;
} }
@ -709,7 +709,7 @@ MRCOwned<id<MTLComputePipelineState>> GSDeviceMTL::MakeComputePipeline(id<MTLFun
{ {
NSString* msg = [NSString stringWithFormat:@"Failed to create pipeline %@: %@", name, [err localizedDescription]]; NSString* msg = [NSString stringWithFormat:@"Failed to create pipeline %@: %@", name, [err localizedDescription]];
Console.Error("%s", [msg UTF8String]); Console.Error("%s", [msg UTF8String]);
throw GSRecoverableError(); pxFailRel("Failed to create pipeline, check the log for more details.");
} }
return res; return res;
} }
@ -914,8 +914,6 @@ bool GSDeviceMTL::Create()
m_features.cas_sharpening = true; m_features.cas_sharpening = true;
m_features.test_and_sample_depth = true; m_features.test_and_sample_depth = true;
try
{
// Init metal stuff // Init metal stuff
m_fn_constants = MRCTransfer([MTLFunctionConstantValues new]); m_fn_constants = MRCTransfer([MTLFunctionConstantValues new]);
setFnConstantB(m_fn_constants, m_dev.features.framebuffer_fetch, GSMTLConstantIndex_FRAMEBUFFER_FETCH); setFnConstantB(m_fn_constants, m_dev.features.framebuffer_fetch, GSMTLConstantIndex_FRAMEBUFFER_FETCH);
@ -1172,11 +1170,6 @@ bool GSDeviceMTL::Create()
m_imgui_pipeline = MakePipeline(pdesc, LoadShader(@"vs_imgui"), LoadShader(@"ps_imgui"), @"imgui"); m_imgui_pipeline = MakePipeline(pdesc, LoadShader(@"vs_imgui"), LoadShader(@"ps_imgui"), @"imgui");
[initCommands commit]; [initCommands commit];
}
catch (GSRecoverableError&)
{
return false;
}
return true; return true;
}} }}

View File

@ -1066,6 +1066,8 @@ GSTexture* GSDeviceOGL::InitPrimDateTexture(GSTexture* rt, const GSVector4i& are
const GSVector2i& rtsize = rt->GetSize(); const GSVector2i& rtsize = rt->GetSize();
GSTexture* tex = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::PrimID, false); GSTexture* tex = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::PrimID, false);
if (!tex)
return nullptr;
GL_PUSH("PrimID Destination Alpha Clear"); GL_PUSH("PrimID Destination Alpha Clear");
StretchRect(rt, GSVector4(area) / GSVector4(rtsize).xyxy(), tex, GSVector4(area), m_date.primid_ps[datm], false); StretchRect(rt, GSVector4(area) / GSVector4(rtsize).xyxy(), tex, GSVector4(area), m_date.primid_ps[datm], false);

View File

@ -20,6 +20,7 @@
#include "xbyak/xbyak.h" #include "xbyak/xbyak.h"
#include "xbyak/xbyak_util.h" #include "xbyak/xbyak_util.h"
#include "GS/MultiISA.h" #include "GS/MultiISA.h"
#include "common/Assertions.h"
/// Code generator that automatically selects between SSE and AVX, x86 and x64 so you don't have to /// Code generator that automatically selects between SSE and AVX, x86 and x64 so you don't have to
/// Should make combined SSE and AVX codegen much easier /// Should make combined SSE and AVX codegen much easier
@ -38,45 +39,11 @@ public:
using Ymm = Xbyak::Ymm; using Ymm = Xbyak::Ymm;
using Zmm = Xbyak::Zmm; using Zmm = Xbyak::Zmm;
class Error : public std::exception
{
public:
enum Value
{
ERR_64_BIT_REG_IN_32,
ERR_64_INSTR_IN_32,
ERR_SSE_INSTR_IN_AVX,
ERR_AVX_INSTR_IN_SSE,
};
Value value;
Error(Value value) : value(value) {}
const char* what() const noexcept
{
static const char* tbl[] = {
"used 64-bit register in 32-bit code",
"used 64-bit only instruction in 32-bit code",
"used SSE instruction in AVX code",
"used AVX instruction in SSE code",
};
if (static_cast<u32>(value) < (sizeof(tbl) / sizeof(*tbl)))
{
return tbl[value];
}
else
{
return "GSNewCodeGenerator Unknown Error";
}
}
};
private: private:
void requireAVX() void requireAVX()
{ {
if (!hasAVX) if (!hasAVX)
throw Error(Error::ERR_AVX_INSTR_IN_SSE); pxFailRel("used AVX instruction in SSE code");
} }
public: public:
@ -141,7 +108,7 @@ public:
#define ACTUAL_FORWARD_SSEONLY(name, ...) \ #define ACTUAL_FORWARD_SSEONLY(name, ...) \
if (hasAVX) \ if (hasAVX) \
throw Error(Error::ERR_SSE_INSTR_IN_AVX); \ pxFailRel("used SSE instruction in AVX code"); \
else \ else \
actual.name(__VA_ARGS__); actual.name(__VA_ARGS__);
@ -149,19 +116,19 @@ public:
if (hasAVX) \ if (hasAVX) \
actual.name(__VA_ARGS__); \ actual.name(__VA_ARGS__); \
else \ else \
throw Error(Error::ERR_AVX_INSTR_IN_SSE); pxFailRel("used AVX instruction in SSE code");
#define ACTUAL_FORWARD_AVX2(name, ...) \ #define ACTUAL_FORWARD_AVX2(name, ...) \
if (hasAVX2) \ if (hasAVX2) \
actual.name(__VA_ARGS__); \ actual.name(__VA_ARGS__); \
else \ else \
throw Error(Error::ERR_AVX_INSTR_IN_SSE); pxFailRel("used AVX instruction in SSE code");
#define ACTUAL_FORWARD_FMA(name, ...) \ #define ACTUAL_FORWARD_FMA(name, ...) \
if (hasFMA) \ if (hasFMA) \
actual.name(__VA_ARGS__); \ actual.name(__VA_ARGS__); \
else \ else \
throw Error(Error::ERR_AVX_INSTR_IN_SSE); pxFailRel("used AVX instruction in SSE code");
#define FORWARD1(category, name, type) \ #define FORWARD1(category, name, type) \
void name(type a) \ void name(type a) \

View File

@ -59,7 +59,7 @@ GSRasterizer::GSRasterizer(GSDrawScanline* ds, int id, int threads)
m_edge.buff = static_cast<GSVertexSW*>(_aligned_malloc(sizeof(GSVertexSW) * 2048, VECTOR_ALIGNMENT)); m_edge.buff = static_cast<GSVertexSW*>(_aligned_malloc(sizeof(GSVertexSW) * 2048, VECTOR_ALIGNMENT));
m_edge.count = 0; m_edge.count = 0;
if (!m_edge.buff) if (!m_edge.buff)
throw std::bad_alloc(); pxFailRel("failed to allocate storage for m_edge.buff");
int rows = (2048 >> m_thread_height) + 16; int rows = (2048 >> m_thread_height) + 16;
m_scanline = (u8*)_aligned_malloc(rows, 64); m_scanline = (u8*)_aligned_malloc(rows, 64);