From a889acb33293afe13642f59be9fcfe8c1d304d00 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 28 Jun 2023 23:05:53 +1000 Subject: [PATCH] GS: Remove exceptions --- pcsx2/GS/GS.cpp | 114 +---- pcsx2/GS/GS.h | 7 - pcsx2/GS/GSClut.cpp | 2 +- pcsx2/GS/GSLocalMemory.cpp | 2 +- pcsx2/GS/GSLzma.cpp | 24 +- pcsx2/GS/GSPng.cpp | 70 ++- pcsx2/GS/GSState.cpp | 24 +- pcsx2/GS/Renderers/Common/GSDevice.cpp | 20 +- pcsx2/GS/Renderers/Common/GSFastList.h | 6 +- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 6 + pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 47 +- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 81 ++-- pcsx2/GS/Renderers/HW/GSTextureCache.h | 5 +- pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm | 499 ++++++++++----------- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 2 + pcsx2/GS/Renderers/SW/GSNewCodeGenerator.h | 45 +- pcsx2/GS/Renderers/SW/GSRasterizer.cpp | 2 +- 17 files changed, 395 insertions(+), 561 deletions(-) diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index 1b474859ea..964017f79e 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -342,52 +342,24 @@ void GSclose() void GSreset(bool hardware_reset) { - try - { - g_gs_renderer->Reset(hardware_reset); - } - catch (GSRecoverableError) - { - } + g_gs_renderer->Reset(hardware_reset); } void GSgifSoftReset(u32 mask) { - try - { - g_gs_renderer->SoftReset(mask); - } - catch (GSRecoverableError) - { - } + g_gs_renderer->SoftReset(mask); } void GSwriteCSR(u32 csr) { - try - { - g_gs_renderer->WriteCSR(csr); - } - catch (GSRecoverableError) - { - } + g_gs_renderer->WriteCSR(csr); } void GSInitAndReadFIFO(u8* mem, u32 size) { GL_PERF("Init and read FIFO %u qwc", size); - try - { - g_gs_renderer->InitReadFIFO(mem, size); - g_gs_renderer->ReadFIFO(mem, size); - } - catch (GSRecoverableError) - { - } - catch (const std::bad_alloc&) - { - fprintf(stderr, "GS: Memory allocation error\n"); - } + g_gs_renderer->InitReadFIFO(mem, size); + g_gs_renderer->ReadFIFO(mem, size); } void GSReadLocalMemoryUnsync(u8* mem, u32 qwc, u64 BITBLITBUF, u64 TRXPOS, u64 TRXREG) @@ -397,89 +369,47 @@ void GSReadLocalMemoryUnsync(u8* mem, u32 qwc, u64 BITBLITBUF, u64 TRXPOS, u64 T void GSgifTransfer(const u8* mem, u32 size) { - try - { - g_gs_renderer->Transfer<3>(mem, size); - } - catch (GSRecoverableError) - { - } + g_gs_renderer->Transfer<3>(mem, size); } void GSgifTransfer1(u8* mem, u32 addr) { - try - { - g_gs_renderer->Transfer<0>(const_cast(mem) + addr, (0x4000 - addr) / 16); - } - catch (GSRecoverableError) - { - } + g_gs_renderer->Transfer<0>(const_cast(mem) + addr, (0x4000 - addr) / 16); } void GSgifTransfer2(u8* mem, u32 size) { - try - { - g_gs_renderer->Transfer<1>(const_cast(mem), size); - } - catch (GSRecoverableError) - { - } + g_gs_renderer->Transfer<1>(const_cast(mem), size); } void GSgifTransfer3(u8* mem, u32 size) { - try - { - g_gs_renderer->Transfer<2>(const_cast(mem), size); - } - catch (GSRecoverableError) - { - } + g_gs_renderer->Transfer<2>(const_cast(mem), size); } void GSvsync(u32 field, bool registers_written) { - try - { - 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"); - } + g_gs_renderer->VSync(field, registers_written, g_gs_renderer->IsIdleFrame()); } int GSfreeze(FreezeAction mode, freezeData* data) { - try + if (mode == FreezeAction::Save) { - if (mode == FreezeAction::Save) - { - return g_gs_renderer->Freeze(data, false); - } - else if (mode == FreezeAction::Size) - { - return g_gs_renderer->Freeze(data, true); - } - else if (mode == FreezeAction::Load) - { - // 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 - // out the current textures. - g_gs_device->ClearCurrent(); - return g_gs_renderer->Defrost(data); - } + return g_gs_renderer->Freeze(data, false); } - catch (GSRecoverableError) + else if (mode == FreezeAction::Size) { + return g_gs_renderer->Freeze(data, true); + } + else // if (mode == FreezeAction::Load) + { + // 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 + // out the current textures. + g_gs_device->ClearCurrent(); + return g_gs_renderer->Defrost(data); } - - return 0; } void GSQueueSnapshot(const std::string& path, u32 gsdump_frames) diff --git a/pcsx2/GS/GS.h b/pcsx2/GS/GS.h index 6087ed125e..1ae15f5049 100644 --- a/pcsx2/GS/GS.h +++ b/pcsx2/GS/GS.h @@ -119,13 +119,6 @@ bool GSSaveSnapshotToMemory(u32 window_width, u32 window_height, bool apply_aspe u32* width, u32* height, std::vector* pixels); void GSJoinSnapshotThreads(); -struct GSError -{ -}; -struct GSRecoverableError : GSError -{ -}; - namespace Host { /// Called when the GS is creating a render device. diff --git a/pcsx2/GS/GSClut.cpp b/pcsx2/GS/GSClut.cpp index a865d9c760..af714bc400 100644 --- a/pcsx2/GS/GSClut.cpp +++ b/pcsx2/GS/GSClut.cpp @@ -30,7 +30,7 @@ GSClut::GSClut(GSLocalMemory* mem) // 1k + 1k for mirrored area simulating wrapping memory m_clut = static_cast(_aligned_malloc(CLUT_ALLOC_SIZE, VECTOR_ALIGNMENT)); if (!m_clut) - throw std::bad_alloc(); + pxFailRel("Failed to allocate CLUT storage."); m_buff32 = reinterpret_cast(reinterpret_cast(m_clut) + 2048); // 1k m_buff64 = reinterpret_cast(reinterpret_cast(m_clut) + 4096); // 2k diff --git a/pcsx2/GS/GSLocalMemory.cpp b/pcsx2/GS/GSLocalMemory.cpp index 5ff022b6d8..c16c796ead 100644 --- a/pcsx2/GS/GSLocalMemory.cpp +++ b/pcsx2/GS/GSLocalMemory.cpp @@ -65,7 +65,7 @@ GSLocalMemory::GSLocalMemory() { m_vm8 = (u8*)GSAllocateWrappedMemory(m_vmsize, 4); if (!m_vm8) - throw std::bad_alloc(); + pxFailRel("Failed to allocate GS memory storage."); memset(m_vm8, 0, m_vmsize); diff --git a/pcsx2/GS/GSLzma.cpp b/pcsx2/GS/GSLzma.cpp index 154b2bfbfe..abd7cbb4ec 100644 --- a/pcsx2/GS/GSLzma.cpp +++ b/pcsx2/GS/GSLzma.cpp @@ -269,8 +269,8 @@ void GSDumpLzma::Initialize() if (ret != LZMA_OK) { - fprintf(stderr, "Error initializing the decoder! (error code %u)\n", ret); - throw "BAD"; // Just exit the program + Console.Error("Error initializing the decoder! (error code %u)", ret); + pxFailRel("Failed to initialize LZMA decoder."); } m_buff_size = 1024*1024; @@ -301,8 +301,8 @@ void GSDumpLzma::Decompress() if (ferror(m_fp)) { - fprintf(stderr, "Read error: %s\n", strerror(errno)); - throw "BAD"; // Just exit the program + Console.Error("Read error: %s", strerror(errno)); + pxFailRel("LZMA read error."); } } @@ -310,12 +310,10 @@ void GSDumpLzma::Decompress() if (ret != LZMA_OK) { - if (ret == LZMA_STREAM_END) - fprintf(stderr, "LZMA decoder finished without error\n\n"); - else + if (ret != LZMA_STREAM_END) { - fprintf(stderr, "Decoder error: (error code %u)\n", ret); - throw "BAD"; // Just exit the program + Console.Error("Decoder error: (error code %u)", ret); + pxFailRel("LZMA decoder error."); } } @@ -395,16 +393,16 @@ void GSDumpDecompressZst::Decompress() if (ferror(m_fp)) { - fprintf(stderr, "Read error: %s\n", strerror(errno)); - throw "BAD"; // Just exit the program + Console.Error("Zst read error: %s", strerror(errno)); + pxFailRel("Zst read error."); } } size_t ret = ZSTD_decompressStream(m_strm, &outbuf, &m_inbuf); if (ZSTD_isError(ret)) { - fprintf(stderr, "Decoder error: (error code %s)\n", ZSTD_getErrorName(ret)); - throw "BAD"; // Just exit the program + Console.Error("Decoder error: (error code %s)", ZSTD_getErrorName(ret)); + pxFailRel("Zst decoder error."); } } diff --git a/pcsx2/GS/GSPng.cpp b/pcsx2/GS/GSPng.cpp index 4008a0cf4f..3d9c88e00b 100644 --- a/pcsx2/GS/GSPng.cpp +++ b/pcsx2/GS/GSPng.cpp @@ -58,53 +58,41 @@ namespace GSPng png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); png_infop info_ptr = nullptr; - bool success; - try + if (png_ptr == nullptr) + return false; + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == nullptr) + return false; + + if (setjmp(png_jmpbuf(png_ptr))) + return false; + + png_init_io(png_ptr, fp); + png_set_compression_level(png_ptr, compression); + png_set_IHDR(png_ptr, info_ptr, width, height, channel_bit_depth, type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + png_write_info(png_ptr, info_ptr); + + if (channel_bit_depth > 8) + png_set_swap(png_ptr); + if (rb_swapped && type != PNG_COLOR_TYPE_GRAY) + png_set_bgr(png_ptr); + + for (int y = 0; y < height; ++y) { - if (png_ptr == nullptr) - throw GSRecoverableError(); - - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == nullptr) - throw GSRecoverableError(); - - if (setjmp(png_jmpbuf(png_ptr))) - throw GSRecoverableError(); - - png_init_io(png_ptr, fp); - png_set_compression_level(png_ptr, compression); - png_set_IHDR(png_ptr, info_ptr, width, height, channel_bit_depth, type, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - png_write_info(png_ptr, info_ptr); - - if (channel_bit_depth > 8) - png_set_swap(png_ptr); - if (rb_swapped && type != PNG_COLOR_TYPE_GRAY) - png_set_bgr(png_ptr); - - for (int y = 0; y < height; ++y) - { - for (int x = 0; x < width; ++x) - for (int i = 0; i < bytes_per_pixel_out; ++i) - row[bytes_per_pixel_out * x + i] = image[y * pitch + bytes_per_pixel_in * x + i + offset]; - png_write_row(png_ptr, row); - } - png_write_end(png_ptr, nullptr); - - success = true; - } - catch (GSRecoverableError&) - { - fprintf(stderr, "Failed to write image %s\n", file.c_str()); - - success = false; + for (int x = 0; x < width; ++x) + for (int i = 0; i < bytes_per_pixel_out; ++i) + row[bytes_per_pixel_out * x + i] = image[y * pitch + bytes_per_pixel_in * x + i + offset]; + png_write_row(png_ptr, row); } + png_write_end(png_ptr, nullptr); if (png_ptr) 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) diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index 204ccd09b6..98b83857de 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -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)); - try - { - // 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); + // 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); - if (!skip_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."); - } + if (!skip_draw) + Draw(); g_perfmon.Put(GSPerfMon::Draw, 1); 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.", vert_byte_count, idx_byte_count); - - throw GSError(); + pxFailRel("Memory allocation failed"); } if (m_vertex.buff) diff --git a/pcsx2/GS/Renderers/Common/GSDevice.cpp b/pcsx2/GS/Renderers/Common/GSDevice.cpp index 6532a1a96e..6a688d7e32 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.cpp +++ b/pcsx2/GS/Renderers/Common/GSDevice.cpp @@ -306,7 +306,15 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i { t = CreateSurface(type, width, height, levels, format); 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; } - GSTexture* new_tex; - try - { - 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); - } - catch (std::bad_alloc&) + const GSTexture::Format fmt = orig_tex ? orig_tex->GetFormat() : GSTexture::Format::Color; + GSTexture* new_tex = FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, fmt, !preserve_contents, true); + if (!new_tex) { Console.WriteLn("%dx%d texture allocation failed in ResizeTexture()", w, h); return false; diff --git a/pcsx2/GS/Renderers/Common/GSFastList.h b/pcsx2/GS/Renderers/Common/GSFastList.h index 2c0797f864..b356ff1be7 100644 --- a/pcsx2/GS/Renderers/Common/GSFastList.h +++ b/pcsx2/GS/Renderers/Common/GSFastList.h @@ -228,9 +228,7 @@ private: void Grow() { if (m_capacity == USHRT_MAX) - { - throw std::runtime_error("FastList size maxed out at USHRT_MAX (65535) elements, cannot grow futhermore."); - } + pxFailRel("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; @@ -247,9 +245,7 @@ private: // Initialize the additional space in the stack for (u16 i = m_capacity - 1; i < new_capacity - 1; i++) - { m_free_indexes_stack[i] = i + 1; - } m_capacity = new_capacity; } diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 8694a63492..042ae03371 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -2212,6 +2212,9 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking) { primid_tex = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::PrimID, false); + if (!primid_tex) + return; + StretchRect(config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(), 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 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy(); hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor); + if (!hdr_rt) + return; + // Warning: StretchRect must be called before BeginScene otherwise // vertices will be overwritten. Trust me you don't want to do that. StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 3f6dc160af..9512992584 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -2004,6 +2004,12 @@ void GSRendererHW::Draw() 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) : 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. @@ -2059,6 +2065,12 @@ void GSRendererHW::Draw() rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, target_scale, GSTextureCache::RenderTarget, true, 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, 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 (!clear_depth && m_cached_ctx.FRAME.FBMSK != 0) { - GSTexture* tex = nullptr; GSTextureCache::Target* target = clear_depth ? ds : rt; - const GSVector2 size = GSVector2(static_cast(target->GetUnscaledWidth()) * target->m_scale, static_cast(target->GetUnscaledHeight()) * target->m_scale); - 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&) - { - } - + GSTexture* tex = g_gs_device->CreateRenderTarget(target->m_texture->GetWidth(), target->m_texture->GetHeight(), target->m_texture->GetFormat(), false); if (!tex) - { - Console.Error("(ResizeTexture) Failed to allocate %dx%d texture", size.x, size.y); return; - } 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 (m_cached_ctx.FRAME.FBMSK != 0) { - GSTexture* tex = nullptr; GSTextureCache::Target* target = rt; - const GSVector2 size = GSVector2(static_cast(target->GetUnscaledWidth()) * target->m_scale, static_cast(target->GetUnscaledHeight()) * target->m_scale); - try - { - tex = g_gs_device->CreateRenderTarget(size.x, size.y, target->m_texture->GetFormat(), true); - } - catch (const std::bad_alloc&) - { - } - + GSTexture* tex = g_gs_device->CreateRenderTarget(target->m_texture->GetWidth(), target->m_texture->GetHeight(), target->m_texture->GetFormat(), true); if (!tex) - { - Console.Error("(ResizeTexture) Failed to allocate %dx%d texture", size.x, size.y); return; - } g_gs_device->ClearRenderTarget(tex, color); diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index d3108a4c03..0fa6182cef 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -579,7 +579,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0 if (GSConfig.UserHacks_DisableDepthSupport) { 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, @@ -756,7 +756,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con 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); - throw GSRecoverableError(); + return nullptr; } const GSVector2i compare_lod(lod ? *lod : GSVector2i(0, 0)); @@ -1382,7 +1382,10 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe if (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->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)); } - 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 // must contains the content of the GS memory. // 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 ((SBP == DBP) && !(GSVector4i(sx, sy, sx + w, sy + h).rintersect(GSVector4i(dx, dy, dx + w, dy + h))).rempty()) { - GSTexture* tmp_texture = nullptr; - const GSVector4i src_size = GSVector4i(src->m_texture->GetSize()).xyxy(); - try - { - 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&) - { - } - + GSTexture* tmp_texture = src->m_texture->IsDepthStencil() ? + g_gs_device->CreateDepthStencil(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false) : + g_gs_device->CreateRenderTarget(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false); if (!tmp_texture) { 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()) { 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)); 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); @@ -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); const int scaled_w = static_cast(std::ceil(static_cast(w) * scale)); const int scaled_h = static_cast(std::ceil(static_cast(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 - // exceptions really need to get lost. - std::unique_ptr t = std::make_unique(TEX0, type); - t->m_unscaled_size = GSVector2i(w, h); - t->m_scale = scale; + Target* t = new Target(TEX0, type, GSVector2i(w, h), scale, texture); - if (type == RenderTarget) - { - t->m_texture = g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear); + g_texture_cache->m_target_memory_usage += t->m_texture->GetMemUsage(); - t->m_used = true; // FIXME - } - else if (type == DepthStencil) - { - t->m_texture = g_gs_device->CreateDepthStencil(scaled_w, scaled_h, GSTexture::Format::DepthStencil, clear); - } + g_texture_cache->m_dst[type].push_front(t); - m_target_memory_usage += t->m_texture->GetMemUsage(); - - m_dst[type].push_front(t.get()); - - return t.release(); + return t; } 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::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_used(false) + , m_used(type == RenderTarget) // FIXME , m_valid(GSVector4i::zero()) { 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); } @@ -4876,19 +4863,9 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca const int new_height = static_cast(std::ceil(new_unscaled_height) * m_scale); 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 - // 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->CreateRenderTarget(new_width, new_height, m_texture->GetFormat(), clear); - } - catch (const std::bad_alloc&) - { - } - + GSTexture* tex = m_texture->IsDepthStencil() ? + g_gs_device->CreateDepthStencil(new_width, new_height, m_texture->GetFormat(), clear) : + g_gs_device->CreateRenderTarget(new_width, new_height, m_texture->GetFormat(), clear); if (!tex) { Console.Error("(ResizeTexture) Failed to allocate %dx%d texture from %dx%d texture", new_width, new_height, width, height); diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 1b31106115..aa9dba76ff 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -227,9 +227,11 @@ public: int readbacks_since_draw = 0; public: - Target(const GIFRegTEX0& TEX0, const int type); + Target(GIFRegTEX0 TEX0, int type, const GSVector2i& unscaled_size, float scale, GSTexture* texture); ~Target(); + static Target* Create(GIFRegTEX0 TEX0, int w, int h, float scale, int type, bool clear); + void ResizeDrawn(const GSVector4i& rect); void UpdateDrawn(const GSVector4i& rect, bool can_resize = true); void ResizeValidity(const GSVector4i& rect); @@ -406,7 +408,6 @@ protected: std::unique_ptr 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); - 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 /// plus the height is larger than the current size of the target. diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm index 20a660ec30..37b75b4736 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm @@ -673,7 +673,7 @@ MRCOwned> GSDeviceMTL::LoadShader(NSString* name) { NSString* msg = [NSString stringWithFormat:@"Failed to load shader %@: %@", name, [err localizedDescription]]; Console.Error("%s", [msg UTF8String]); - throw GSRecoverableError(); + pxFailRel("Failed to load shader, check the log for more details."); } return fn; } @@ -689,7 +689,7 @@ MRCOwned> GSDeviceMTL::MakePipeline(MTLRenderPipeline { NSString* msg = [NSString stringWithFormat:@"Failed to create pipeline %@: %@", name, [err localizedDescription]]; Console.Error("%s", [msg UTF8String]); - throw GSRecoverableError(); + pxFailRel("Failed to create pipeline, check the log for more details."); } return res; } @@ -709,7 +709,7 @@ MRCOwned> GSDeviceMTL::MakeComputePipeline(id initCommands = [m_queue commandBuffer]; + id clearSpinBuffer = [initCommands blitCommandEncoder]; + [clearSpinBuffer fillBuffer:m_spin_buffer range:NSMakeRange(0, 4) value:0]; + [clearSpinBuffer updateFence:m_spin_fence]; + [clearSpinBuffer endEncoding]; + m_spin_pipeline = MakeComputePipeline(LoadShader(@"waste_time"), @"waste_time"); + + for (int sharpen_only = 0; sharpen_only < 2; sharpen_only++) { - // Init metal stuff - m_fn_constants = MRCTransfer([MTLFunctionConstantValues new]); - setFnConstantB(m_fn_constants, m_dev.features.framebuffer_fetch, GSMTLConstantIndex_FRAMEBUFFER_FETCH); + setFnConstantB(m_fn_constants, sharpen_only, GSMTLConstantIndex_CAS_SHARPEN_ONLY); + NSString* shader = m_dev.features.has_fast_half ? @"CASHalf" : @"CASFloat"; + m_cas_pipeline[sharpen_only] = MakeComputePipeline(LoadShader(shader), sharpen_only ? @"CAS Sharpen" : @"CAS Upscale"); + } - m_draw_sync_fence = MRCTransfer([m_dev.dev newFence]); - [m_draw_sync_fence setLabel:@"Draw Sync Fence"]; - m_spin_fence = MRCTransfer([m_dev.dev newFence]); - [m_spin_fence setLabel:@"Spin Fence"]; - constexpr MTLResourceOptions spin_opts = MTLResourceStorageModePrivate | MTLResourceHazardTrackingModeUntracked; - m_spin_buffer = MRCTransfer([m_dev.dev newBufferWithLength:4 options:spin_opts]); - [m_spin_buffer setLabel:@"Spin Buffer"]; - id initCommands = [m_queue commandBuffer]; - id clearSpinBuffer = [initCommands blitCommandEncoder]; - [clearSpinBuffer fillBuffer:m_spin_buffer range:NSMakeRange(0, 4) value:0]; - [clearSpinBuffer updateFence:m_spin_fence]; - [clearSpinBuffer endEncoding]; - m_spin_pipeline = MakeComputePipeline(LoadShader(@"waste_time"), @"waste_time"); + m_expand_index_buffer = CreatePrivateBufferWithContent(m_dev.dev, initCommands, MTLResourceHazardTrackingModeUntracked, EXPAND_BUFFER_SIZE, GenerateExpansionIndexBuffer); + [m_expand_index_buffer setLabel:@"Point/Sprite Expand Indices"]; - for (int sharpen_only = 0; sharpen_only < 2; sharpen_only++) + m_hw_vertex = MRCTransfer([MTLVertexDescriptor new]); + [[[m_hw_vertex layouts] objectAtIndexedSubscript:GSMTLBufferIndexHWVertices] setStride:sizeof(GSVertex)]; + applyAttribute(m_hw_vertex, GSMTLAttributeIndexST, MTLVertexFormatFloat2, offsetof(GSVertex, ST), GSMTLBufferIndexHWVertices); + applyAttribute(m_hw_vertex, GSMTLAttributeIndexC, MTLVertexFormatUChar4, offsetof(GSVertex, RGBAQ.R), GSMTLBufferIndexHWVertices); + applyAttribute(m_hw_vertex, GSMTLAttributeIndexQ, MTLVertexFormatFloat, offsetof(GSVertex, RGBAQ.Q), GSMTLBufferIndexHWVertices); + applyAttribute(m_hw_vertex, GSMTLAttributeIndexXY, MTLVertexFormatUShort2, offsetof(GSVertex, XYZ.X), GSMTLBufferIndexHWVertices); + applyAttribute(m_hw_vertex, GSMTLAttributeIndexZ, MTLVertexFormatUInt, offsetof(GSVertex, XYZ.Z), GSMTLBufferIndexHWVertices); + applyAttribute(m_hw_vertex, GSMTLAttributeIndexUV, MTLVertexFormatUShort2, offsetof(GSVertex, UV), GSMTLBufferIndexHWVertices); + applyAttribute(m_hw_vertex, GSMTLAttributeIndexF, MTLVertexFormatUChar4Normalized, offsetof(GSVertex, FOG), GSMTLBufferIndexHWVertices); + + for (auto& desc : m_render_pass_desc) + { + desc = MRCTransfer([MTLRenderPassDescriptor new]); + [[desc depthAttachment] setStoreAction:MTLStoreActionStore]; + [[desc stencilAttachment] setStoreAction:MTLStoreActionStore]; + } + + // Init samplers + m_sampler_hw[SamplerSelector::Linear().key] = CreateSampler(m_dev.dev, SamplerSelector::Linear()); + m_sampler_hw[SamplerSelector::Point().key] = CreateSampler(m_dev.dev, SamplerSelector::Point()); + + // Init depth stencil states + MTLDepthStencilDescriptor* dssdesc = [[MTLDepthStencilDescriptor new] autorelease]; + MTLStencilDescriptor* stencildesc = [[MTLStencilDescriptor new] autorelease]; + stencildesc.stencilCompareFunction = MTLCompareFunctionAlways; + stencildesc.depthFailureOperation = MTLStencilOperationKeep; + stencildesc.stencilFailureOperation = MTLStencilOperationKeep; + stencildesc.depthStencilPassOperation = MTLStencilOperationReplace; + dssdesc.frontFaceStencil = stencildesc; + dssdesc.backFaceStencil = stencildesc; + [dssdesc setLabel:@"Stencil Write"]; + m_dss_stencil_write = MRCTransfer([m_dev.dev newDepthStencilStateWithDescriptor:dssdesc]); + dssdesc.frontFaceStencil.depthStencilPassOperation = MTLStencilOperationZero; + dssdesc.backFaceStencil.depthStencilPassOperation = MTLStencilOperationZero; + [dssdesc setLabel:@"Stencil Zero"]; + m_dss_stencil_zero = MRCTransfer([m_dev.dev newDepthStencilStateWithDescriptor:dssdesc]); + stencildesc.stencilCompareFunction = MTLCompareFunctionEqual; + stencildesc.readMask = 1; + stencildesc.writeMask = 1; + for (size_t i = 0; i < std::size(m_dss_hw); i++) + { + GSHWDrawConfig::DepthStencilSelector sel; + sel.key = i; + if (sel.date) { - setFnConstantB(m_fn_constants, sharpen_only, GSMTLConstantIndex_CAS_SHARPEN_ONLY); - NSString* shader = m_dev.features.has_fast_half ? @"CASHalf" : @"CASFloat"; - m_cas_pipeline[sharpen_only] = MakeComputePipeline(LoadShader(shader), sharpen_only ? @"CAS Sharpen" : @"CAS Upscale"); - } - - m_expand_index_buffer = CreatePrivateBufferWithContent(m_dev.dev, initCommands, MTLResourceHazardTrackingModeUntracked, EXPAND_BUFFER_SIZE, GenerateExpansionIndexBuffer); - [m_expand_index_buffer setLabel:@"Point/Sprite Expand Indices"]; - - m_hw_vertex = MRCTransfer([MTLVertexDescriptor new]); - [[[m_hw_vertex layouts] objectAtIndexedSubscript:GSMTLBufferIndexHWVertices] setStride:sizeof(GSVertex)]; - applyAttribute(m_hw_vertex, GSMTLAttributeIndexST, MTLVertexFormatFloat2, offsetof(GSVertex, ST), GSMTLBufferIndexHWVertices); - applyAttribute(m_hw_vertex, GSMTLAttributeIndexC, MTLVertexFormatUChar4, offsetof(GSVertex, RGBAQ.R), GSMTLBufferIndexHWVertices); - applyAttribute(m_hw_vertex, GSMTLAttributeIndexQ, MTLVertexFormatFloat, offsetof(GSVertex, RGBAQ.Q), GSMTLBufferIndexHWVertices); - applyAttribute(m_hw_vertex, GSMTLAttributeIndexXY, MTLVertexFormatUShort2, offsetof(GSVertex, XYZ.X), GSMTLBufferIndexHWVertices); - applyAttribute(m_hw_vertex, GSMTLAttributeIndexZ, MTLVertexFormatUInt, offsetof(GSVertex, XYZ.Z), GSMTLBufferIndexHWVertices); - applyAttribute(m_hw_vertex, GSMTLAttributeIndexUV, MTLVertexFormatUShort2, offsetof(GSVertex, UV), GSMTLBufferIndexHWVertices); - applyAttribute(m_hw_vertex, GSMTLAttributeIndexF, MTLVertexFormatUChar4Normalized, offsetof(GSVertex, FOG), GSMTLBufferIndexHWVertices); - - for (auto& desc : m_render_pass_desc) - { - desc = MRCTransfer([MTLRenderPassDescriptor new]); - [[desc depthAttachment] setStoreAction:MTLStoreActionStore]; - [[desc stencilAttachment] setStoreAction:MTLStoreActionStore]; - } - - // Init samplers - m_sampler_hw[SamplerSelector::Linear().key] = CreateSampler(m_dev.dev, SamplerSelector::Linear()); - m_sampler_hw[SamplerSelector::Point().key] = CreateSampler(m_dev.dev, SamplerSelector::Point()); - - // Init depth stencil states - MTLDepthStencilDescriptor* dssdesc = [[MTLDepthStencilDescriptor new] autorelease]; - MTLStencilDescriptor* stencildesc = [[MTLStencilDescriptor new] autorelease]; - stencildesc.stencilCompareFunction = MTLCompareFunctionAlways; - stencildesc.depthFailureOperation = MTLStencilOperationKeep; - stencildesc.stencilFailureOperation = MTLStencilOperationKeep; - stencildesc.depthStencilPassOperation = MTLStencilOperationReplace; - dssdesc.frontFaceStencil = stencildesc; - dssdesc.backFaceStencil = stencildesc; - [dssdesc setLabel:@"Stencil Write"]; - m_dss_stencil_write = MRCTransfer([m_dev.dev newDepthStencilStateWithDescriptor:dssdesc]); - dssdesc.frontFaceStencil.depthStencilPassOperation = MTLStencilOperationZero; - dssdesc.backFaceStencil.depthStencilPassOperation = MTLStencilOperationZero; - [dssdesc setLabel:@"Stencil Zero"]; - m_dss_stencil_zero = MRCTransfer([m_dev.dev newDepthStencilStateWithDescriptor:dssdesc]); - stencildesc.stencilCompareFunction = MTLCompareFunctionEqual; - stencildesc.readMask = 1; - stencildesc.writeMask = 1; - for (size_t i = 0; i < std::size(m_dss_hw); i++) - { - GSHWDrawConfig::DepthStencilSelector sel; - sel.key = i; - if (sel.date) - { - if (sel.date_one) - stencildesc.depthStencilPassOperation = MTLStencilOperationZero; - else - stencildesc.depthStencilPassOperation = MTLStencilOperationKeep; - dssdesc.frontFaceStencil = stencildesc; - dssdesc.backFaceStencil = stencildesc; - } + if (sel.date_one) + stencildesc.depthStencilPassOperation = MTLStencilOperationZero; else - { - dssdesc.frontFaceStencil = nil; - dssdesc.backFaceStencil = nil; - } - dssdesc.depthWriteEnabled = sel.zwe ? YES : NO; - static constexpr MTLCompareFunction ztst[] = - { - MTLCompareFunctionNever, - MTLCompareFunctionAlways, - MTLCompareFunctionGreaterEqual, - MTLCompareFunctionGreater, - }; - static constexpr const char* ztstname[] = - { - "DepthNever", - "DepthAlways", - "DepthGEq", - "DepthEq", - }; - const char* datedesc = sel.date ? (sel.date_one ? " DATE_ONE" : " DATE") : ""; - const char* zwedesc = sel.zwe ? " ZWE" : ""; - dssdesc.depthCompareFunction = ztst[sel.ztst]; - [dssdesc setLabel:[NSString stringWithFormat:@"%s%s%s", ztstname[sel.ztst], zwedesc, datedesc]]; - m_dss_hw[i] = MRCTransfer([m_dev.dev newDepthStencilStateWithDescriptor:dssdesc]); + stencildesc.depthStencilPassOperation = MTLStencilOperationKeep; + dssdesc.frontFaceStencil = stencildesc; + dssdesc.backFaceStencil = stencildesc; } - - // Init HW Vertex Shaders - for (size_t i = 0; i < std::size(m_hw_vs); i++) + else { - VSSelector sel; - sel.key = i; - if (sel.point_size && sel.expand != GSMTLExpandType::None) - continue; - setFnConstantB(m_fn_constants, sel.fst, GSMTLConstantIndex_FST); - setFnConstantB(m_fn_constants, sel.iip, GSMTLConstantIndex_IIP); - setFnConstantB(m_fn_constants, sel.point_size, GSMTLConstantIndex_VS_POINT_SIZE); - NSString* shader = @"vs_main"; - if (sel.expand != GSMTLExpandType::None) - { - setFnConstantI(m_fn_constants, static_cast(sel.expand), GSMTLConstantIndex_VS_EXPAND_TYPE); - shader = @"vs_main_expand"; - } - m_hw_vs[i] = LoadShader(shader); + dssdesc.frontFaceStencil = nil; + dssdesc.backFaceStencil = nil; } - - // Init pipelines - auto vs_convert = LoadShader(@"vs_convert"); - auto fs_triangle = LoadShader(@"fs_triangle"); - auto ps_copy = LoadShader(@"ps_copy"); - auto pdesc = [[MTLRenderPipelineDescriptor new] autorelease]; - // FS Triangle Pipelines - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color); - m_hdr_resolve_pipeline = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_hdr_resolve"), @"HDR Resolve"); - m_fxaa_pipeline = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_fxaa"), @"fxaa"); - m_shadeboost_pipeline = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_shadeboost"), @"shadeboost"); - m_clut_pipeline[0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_convert_clut_4"), @"4-bit CLUT Update"); - m_clut_pipeline[1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_convert_clut_8"), @"8-bit CLUT Update"); - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::HDRColor); - m_hdr_init_pipeline = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_hdr_init"), @"HDR Init"); - pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatInvalid; - pdesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - m_datm_pipeline[0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_datm0"), @"datm0"); - m_datm_pipeline[1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_datm1"), @"datm1"); - m_stencil_clear_pipeline = MakePipeline(pdesc, fs_triangle, nil, @"Stencil Clear"); - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::PrimID); - pdesc.stencilAttachmentPixelFormat = MTLPixelFormatInvalid; - pdesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - m_primid_init_pipeline[1][0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm0"), @"PrimID DATM0 Clear"); - m_primid_init_pipeline[1][1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm1"), @"PrimID DATM1 Clear"); - pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; - m_primid_init_pipeline[0][0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm0"), @"PrimID DATM0 Clear"); - m_primid_init_pipeline[0][1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm1"), @"PrimID DATM1 Clear"); - - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color); - applyAttribute(pdesc.vertexDescriptor, 0, MTLVertexFormatFloat2, offsetof(ConvertShaderVertex, pos), 0); - applyAttribute(pdesc.vertexDescriptor, 1, MTLVertexFormatFloat2, offsetof(ConvertShaderVertex, texpos), 0); - pdesc.vertexDescriptor.layouts[0].stride = sizeof(ConvertShaderVertex); - - for (size_t i = 0; i < std::size(m_interlace_pipeline); i++) + dssdesc.depthWriteEnabled = sel.zwe ? YES : NO; + static constexpr MTLCompareFunction ztst[] = { - NSString* name = [NSString stringWithFormat:@"ps_interlace%zu", i]; - m_interlace_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), name); - } - for (size_t i = 0; i < std::size(m_convert_pipeline); i++) + MTLCompareFunctionNever, + MTLCompareFunctionAlways, + MTLCompareFunctionGreaterEqual, + MTLCompareFunctionGreater, + }; + static constexpr const char* ztstname[] = { - ShaderConvert conv = static_cast(i); - NSString* name = [NSString stringWithCString:shaderName(conv) encoding:NSUTF8StringEncoding]; - switch (conv) - { - case ShaderConvert::Count: - case ShaderConvert::DATM_0: - case ShaderConvert::DATM_1: - case ShaderConvert::CLUT_4: - case ShaderConvert::CLUT_8: - case ShaderConvert::HDR_INIT: - case ShaderConvert::HDR_RESOLVE: - continue; - case ShaderConvert::FLOAT32_TO_32_BITS: - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::UInt32); - pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; - break; - case ShaderConvert::FLOAT32_TO_16_BITS: - case ShaderConvert::RGBA8_TO_16_BITS: - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::UInt16); - pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; - break; - case ShaderConvert::DEPTH_COPY: - case ShaderConvert::RGBA8_TO_FLOAT32: - case ShaderConvert::RGBA8_TO_FLOAT24: - case ShaderConvert::RGBA8_TO_FLOAT16: - case ShaderConvert::RGB5A1_TO_FLOAT16: - case ShaderConvert::RGBA8_TO_FLOAT32_BILN: - case ShaderConvert::RGBA8_TO_FLOAT24_BILN: - case ShaderConvert::RGBA8_TO_FLOAT16_BILN: - case ShaderConvert::RGB5A1_TO_FLOAT16_BILN: - pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatInvalid; - pdesc.depthAttachmentPixelFormat = ConvertPixelFormat(GSTexture::Format::DepthStencil); - break; - case ShaderConvert::COPY: - case ShaderConvert::RGBA_TO_8I: // Yes really - case ShaderConvert::TRANSPARENCY_FILTER: - case ShaderConvert::FLOAT32_TO_RGBA8: - case ShaderConvert::FLOAT16_TO_RGB5A1: - case ShaderConvert::YUV: - pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color); - pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; - break; - } - m_convert_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), name); - } - pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; - for (size_t i = 0; i < std::size(m_present_pipeline); i++) - { - PresentShader conv = static_cast(i); - NSString* name = [NSString stringWithCString:shaderName(conv) encoding:NSUTF8StringEncoding]; - pdesc.colorAttachments[0].pixelFormat = layer_px_fmt; - m_present_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), [NSString stringWithFormat:@"present_%s", shaderName(conv) + 3]); - } - - pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm; - for (size_t i = 0; i < std::size(m_convert_pipeline_copy_mask); i++) - { - MTLColorWriteMask mask = MTLColorWriteMaskNone; - if (i & 1) mask |= MTLColorWriteMaskRed; - if (i & 2) mask |= MTLColorWriteMaskGreen; - if (i & 4) mask |= MTLColorWriteMaskBlue; - if (i & 8) mask |= MTLColorWriteMaskAlpha; - NSString* name = [NSString stringWithFormat:@"copy_%s%s%s%s", i & 1 ? "r" : "", i & 2 ? "g" : "", i & 4 ? "b" : "", i & 8 ? "a" : ""]; - pdesc.colorAttachments[0].writeMask = mask; - m_convert_pipeline_copy_mask[i] = MakePipeline(pdesc, vs_convert, ps_copy, name); - } - - pdesc.colorAttachments[0].blendingEnabled = YES; - pdesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; - pdesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; - pdesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; - for (size_t i = 0; i < std::size(m_merge_pipeline); i++) - { - bool mmod = i & 1; - bool amod = i & 2; - NSString* name = [NSString stringWithFormat:@"ps_merge%zu", mmod]; - NSString* pipename = [NSString stringWithFormat:@"Merge%s%s", mmod ? " MMOD" : "", amod ? " AMOD" : ""]; - pdesc.colorAttachments[0].writeMask = amod ? MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue : MTLColorWriteMaskAll; - m_merge_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), pipename); - } - pdesc.colorAttachments[0].writeMask = MTLColorWriteMaskAll; - - applyAttribute(pdesc.vertexDescriptor, 0, MTLVertexFormatFloat2, offsetof(ImDrawVert, pos), 0); - applyAttribute(pdesc.vertexDescriptor, 1, MTLVertexFormatFloat2, offsetof(ImDrawVert, uv), 0); - applyAttribute(pdesc.vertexDescriptor, 2, MTLVertexFormatUChar4Normalized, offsetof(ImDrawVert, col), 0); - pdesc.vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert); - pdesc.colorAttachments[0].pixelFormat = layer_px_fmt; - m_imgui_pipeline = MakePipeline(pdesc, LoadShader(@"vs_imgui"), LoadShader(@"ps_imgui"), @"imgui"); - - [initCommands commit]; + "DepthNever", + "DepthAlways", + "DepthGEq", + "DepthEq", + }; + const char* datedesc = sel.date ? (sel.date_one ? " DATE_ONE" : " DATE") : ""; + const char* zwedesc = sel.zwe ? " ZWE" : ""; + dssdesc.depthCompareFunction = ztst[sel.ztst]; + [dssdesc setLabel:[NSString stringWithFormat:@"%s%s%s", ztstname[sel.ztst], zwedesc, datedesc]]; + m_dss_hw[i] = MRCTransfer([m_dev.dev newDepthStencilStateWithDescriptor:dssdesc]); } - catch (GSRecoverableError&) + + // Init HW Vertex Shaders + for (size_t i = 0; i < std::size(m_hw_vs); i++) { - return false; + VSSelector sel; + sel.key = i; + if (sel.point_size && sel.expand != GSMTLExpandType::None) + continue; + setFnConstantB(m_fn_constants, sel.fst, GSMTLConstantIndex_FST); + setFnConstantB(m_fn_constants, sel.iip, GSMTLConstantIndex_IIP); + setFnConstantB(m_fn_constants, sel.point_size, GSMTLConstantIndex_VS_POINT_SIZE); + NSString* shader = @"vs_main"; + if (sel.expand != GSMTLExpandType::None) + { + setFnConstantI(m_fn_constants, static_cast(sel.expand), GSMTLConstantIndex_VS_EXPAND_TYPE); + shader = @"vs_main_expand"; + } + m_hw_vs[i] = LoadShader(shader); } + + // Init pipelines + auto vs_convert = LoadShader(@"vs_convert"); + auto fs_triangle = LoadShader(@"fs_triangle"); + auto ps_copy = LoadShader(@"ps_copy"); + auto pdesc = [[MTLRenderPipelineDescriptor new] autorelease]; + // FS Triangle Pipelines + pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color); + m_hdr_resolve_pipeline = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_hdr_resolve"), @"HDR Resolve"); + m_fxaa_pipeline = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_fxaa"), @"fxaa"); + m_shadeboost_pipeline = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_shadeboost"), @"shadeboost"); + m_clut_pipeline[0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_convert_clut_4"), @"4-bit CLUT Update"); + m_clut_pipeline[1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_convert_clut_8"), @"8-bit CLUT Update"); + pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::HDRColor); + m_hdr_init_pipeline = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_hdr_init"), @"HDR Init"); + pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatInvalid; + pdesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + m_datm_pipeline[0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_datm0"), @"datm0"); + m_datm_pipeline[1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_datm1"), @"datm1"); + m_stencil_clear_pipeline = MakePipeline(pdesc, fs_triangle, nil, @"Stencil Clear"); + pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::PrimID); + pdesc.stencilAttachmentPixelFormat = MTLPixelFormatInvalid; + pdesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + m_primid_init_pipeline[1][0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm0"), @"PrimID DATM0 Clear"); + m_primid_init_pipeline[1][1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm1"), @"PrimID DATM1 Clear"); + pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; + m_primid_init_pipeline[0][0] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm0"), @"PrimID DATM0 Clear"); + m_primid_init_pipeline[0][1] = MakePipeline(pdesc, fs_triangle, LoadShader(@"ps_primid_init_datm1"), @"PrimID DATM1 Clear"); + + pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color); + applyAttribute(pdesc.vertexDescriptor, 0, MTLVertexFormatFloat2, offsetof(ConvertShaderVertex, pos), 0); + applyAttribute(pdesc.vertexDescriptor, 1, MTLVertexFormatFloat2, offsetof(ConvertShaderVertex, texpos), 0); + pdesc.vertexDescriptor.layouts[0].stride = sizeof(ConvertShaderVertex); + + for (size_t i = 0; i < std::size(m_interlace_pipeline); i++) + { + NSString* name = [NSString stringWithFormat:@"ps_interlace%zu", i]; + m_interlace_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), name); + } + for (size_t i = 0; i < std::size(m_convert_pipeline); i++) + { + ShaderConvert conv = static_cast(i); + NSString* name = [NSString stringWithCString:shaderName(conv) encoding:NSUTF8StringEncoding]; + switch (conv) + { + case ShaderConvert::Count: + case ShaderConvert::DATM_0: + case ShaderConvert::DATM_1: + case ShaderConvert::CLUT_4: + case ShaderConvert::CLUT_8: + case ShaderConvert::HDR_INIT: + case ShaderConvert::HDR_RESOLVE: + continue; + case ShaderConvert::FLOAT32_TO_32_BITS: + pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::UInt32); + pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; + break; + case ShaderConvert::FLOAT32_TO_16_BITS: + case ShaderConvert::RGBA8_TO_16_BITS: + pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::UInt16); + pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; + break; + case ShaderConvert::DEPTH_COPY: + case ShaderConvert::RGBA8_TO_FLOAT32: + case ShaderConvert::RGBA8_TO_FLOAT24: + case ShaderConvert::RGBA8_TO_FLOAT16: + case ShaderConvert::RGB5A1_TO_FLOAT16: + case ShaderConvert::RGBA8_TO_FLOAT32_BILN: + case ShaderConvert::RGBA8_TO_FLOAT24_BILN: + case ShaderConvert::RGBA8_TO_FLOAT16_BILN: + case ShaderConvert::RGB5A1_TO_FLOAT16_BILN: + pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatInvalid; + pdesc.depthAttachmentPixelFormat = ConvertPixelFormat(GSTexture::Format::DepthStencil); + break; + case ShaderConvert::COPY: + case ShaderConvert::RGBA_TO_8I: // Yes really + case ShaderConvert::TRANSPARENCY_FILTER: + case ShaderConvert::FLOAT32_TO_RGBA8: + case ShaderConvert::FLOAT16_TO_RGB5A1: + case ShaderConvert::YUV: + pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color); + pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; + break; + } + m_convert_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), name); + } + pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid; + for (size_t i = 0; i < std::size(m_present_pipeline); i++) + { + PresentShader conv = static_cast(i); + NSString* name = [NSString stringWithCString:shaderName(conv) encoding:NSUTF8StringEncoding]; + pdesc.colorAttachments[0].pixelFormat = layer_px_fmt; + m_present_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), [NSString stringWithFormat:@"present_%s", shaderName(conv) + 3]); + } + + pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm; + for (size_t i = 0; i < std::size(m_convert_pipeline_copy_mask); i++) + { + MTLColorWriteMask mask = MTLColorWriteMaskNone; + if (i & 1) mask |= MTLColorWriteMaskRed; + if (i & 2) mask |= MTLColorWriteMaskGreen; + if (i & 4) mask |= MTLColorWriteMaskBlue; + if (i & 8) mask |= MTLColorWriteMaskAlpha; + NSString* name = [NSString stringWithFormat:@"copy_%s%s%s%s", i & 1 ? "r" : "", i & 2 ? "g" : "", i & 4 ? "b" : "", i & 8 ? "a" : ""]; + pdesc.colorAttachments[0].writeMask = mask; + m_convert_pipeline_copy_mask[i] = MakePipeline(pdesc, vs_convert, ps_copy, name); + } + + pdesc.colorAttachments[0].blendingEnabled = YES; + pdesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; + pdesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + pdesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + for (size_t i = 0; i < std::size(m_merge_pipeline); i++) + { + bool mmod = i & 1; + bool amod = i & 2; + NSString* name = [NSString stringWithFormat:@"ps_merge%zu", mmod]; + NSString* pipename = [NSString stringWithFormat:@"Merge%s%s", mmod ? " MMOD" : "", amod ? " AMOD" : ""]; + pdesc.colorAttachments[0].writeMask = amod ? MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue : MTLColorWriteMaskAll; + m_merge_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), pipename); + } + pdesc.colorAttachments[0].writeMask = MTLColorWriteMaskAll; + + applyAttribute(pdesc.vertexDescriptor, 0, MTLVertexFormatFloat2, offsetof(ImDrawVert, pos), 0); + applyAttribute(pdesc.vertexDescriptor, 1, MTLVertexFormatFloat2, offsetof(ImDrawVert, uv), 0); + applyAttribute(pdesc.vertexDescriptor, 2, MTLVertexFormatUChar4Normalized, offsetof(ImDrawVert, col), 0); + pdesc.vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert); + pdesc.colorAttachments[0].pixelFormat = layer_px_fmt; + m_imgui_pipeline = MakePipeline(pdesc, LoadShader(@"vs_imgui"), LoadShader(@"ps_imgui"), @"imgui"); + + [initCommands commit]; return true; }} diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index 22a112e517..24b045526b 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -1066,6 +1066,8 @@ GSTexture* GSDeviceOGL::InitPrimDateTexture(GSTexture* rt, const GSVector4i& are const GSVector2i& rtsize = rt->GetSize(); GSTexture* tex = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::PrimID, false); + if (!tex) + return nullptr; GL_PUSH("PrimID Destination Alpha Clear"); StretchRect(rt, GSVector4(area) / GSVector4(rtsize).xyxy(), tex, GSVector4(area), m_date.primid_ps[datm], false); diff --git a/pcsx2/GS/Renderers/SW/GSNewCodeGenerator.h b/pcsx2/GS/Renderers/SW/GSNewCodeGenerator.h index 4f7cbbf9ad..2404d27936 100644 --- a/pcsx2/GS/Renderers/SW/GSNewCodeGenerator.h +++ b/pcsx2/GS/Renderers/SW/GSNewCodeGenerator.h @@ -20,6 +20,7 @@ #include "xbyak/xbyak.h" #include "xbyak/xbyak_util.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 /// Should make combined SSE and AVX codegen much easier @@ -38,45 +39,11 @@ public: using Ymm = Xbyak::Ymm; 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(value) < (sizeof(tbl) / sizeof(*tbl))) - { - return tbl[value]; - } - else - { - return "GSNewCodeGenerator Unknown Error"; - } - } - }; - private: void requireAVX() { if (!hasAVX) - throw Error(Error::ERR_AVX_INSTR_IN_SSE); + pxFailRel("used AVX instruction in SSE code"); } public: @@ -141,7 +108,7 @@ public: #define ACTUAL_FORWARD_SSEONLY(name, ...) \ if (hasAVX) \ - throw Error(Error::ERR_SSE_INSTR_IN_AVX); \ + pxFailRel("used SSE instruction in AVX code"); \ else \ actual.name(__VA_ARGS__); @@ -149,19 +116,19 @@ public: if (hasAVX) \ actual.name(__VA_ARGS__); \ else \ - throw Error(Error::ERR_AVX_INSTR_IN_SSE); + pxFailRel("used AVX instruction in SSE code"); #define ACTUAL_FORWARD_AVX2(name, ...) \ if (hasAVX2) \ actual.name(__VA_ARGS__); \ else \ - throw Error(Error::ERR_AVX_INSTR_IN_SSE); + pxFailRel("used AVX instruction in SSE code"); #define ACTUAL_FORWARD_FMA(name, ...) \ if (hasFMA) \ actual.name(__VA_ARGS__); \ else \ - throw Error(Error::ERR_AVX_INSTR_IN_SSE); + pxFailRel("used AVX instruction in SSE code"); #define FORWARD1(category, name, type) \ void name(type a) \ diff --git a/pcsx2/GS/Renderers/SW/GSRasterizer.cpp b/pcsx2/GS/Renderers/SW/GSRasterizer.cpp index bda2e9e169..dbf719addb 100644 --- a/pcsx2/GS/Renderers/SW/GSRasterizer.cpp +++ b/pcsx2/GS/Renderers/SW/GSRasterizer.cpp @@ -59,7 +59,7 @@ GSRasterizer::GSRasterizer(GSDrawScanline* ds, int id, int threads) m_edge.buff = static_cast(_aligned_malloc(sizeof(GSVertexSW) * 2048, VECTOR_ALIGNMENT)); m_edge.count = 0; if (!m_edge.buff) - throw std::bad_alloc(); + pxFailRel("failed to allocate storage for m_edge.buff"); int rows = (2048 >> m_thread_height) + 16; m_scanline = (u8*)_aligned_malloc(rows, 64);