mirror of https://github.com/PCSX2/pcsx2.git
GS: Remove exceptions
This commit is contained in:
parent
81236209db
commit
a889acb332
114
pcsx2/GS/GS.cpp
114
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<u8*>(mem) + addr, (0x4000 - addr) / 16);
|
||||
}
|
||||
catch (GSRecoverableError)
|
||||
{
|
||||
}
|
||||
g_gs_renderer->Transfer<0>(const_cast<u8*>(mem) + addr, (0x4000 - addr) / 16);
|
||||
}
|
||||
|
||||
void GSgifTransfer2(u8* mem, u32 size)
|
||||
{
|
||||
try
|
||||
{
|
||||
g_gs_renderer->Transfer<1>(const_cast<u8*>(mem), size);
|
||||
}
|
||||
catch (GSRecoverableError)
|
||||
{
|
||||
}
|
||||
g_gs_renderer->Transfer<1>(const_cast<u8*>(mem), size);
|
||||
}
|
||||
|
||||
void GSgifTransfer3(u8* mem, u32 size)
|
||||
{
|
||||
try
|
||||
{
|
||||
g_gs_renderer->Transfer<2>(const_cast<u8*>(mem), size);
|
||||
}
|
||||
catch (GSRecoverableError)
|
||||
{
|
||||
}
|
||||
g_gs_renderer->Transfer<2>(const_cast<u8*>(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)
|
||||
|
|
|
@ -119,13 +119,6 @@ bool GSSaveSnapshotToMemory(u32 window_width, u32 window_height, bool apply_aspe
|
|||
u32* width, u32* height, std::vector<u32>* pixels);
|
||||
void GSJoinSnapshotThreads();
|
||||
|
||||
struct GSError
|
||||
{
|
||||
};
|
||||
struct GSRecoverableError : GSError
|
||||
{
|
||||
};
|
||||
|
||||
namespace Host
|
||||
{
|
||||
/// Called when the GS is creating a render device.
|
||||
|
|
|
@ -30,7 +30,7 @@ GSClut::GSClut(GSLocalMemory* mem)
|
|||
// 1k + 1k for mirrored area simulating wrapping memory
|
||||
m_clut = static_cast<u16*>(_aligned_malloc(CLUT_ALLOC_SIZE, VECTOR_ALIGNMENT));
|
||||
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_buff64 = reinterpret_cast<u64*>(reinterpret_cast<u8*>(m_clut) + 4096); // 2k
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<float>(target->GetUnscaledWidth()) * target->m_scale, static_cast<float>(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<float>(target->GetUnscaledWidth()) * target->m_scale, static_cast<float>(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);
|
||||
|
||||
|
|
|
@ -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<int>(std::ceil(static_cast<float>(w) * 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
|
||||
// 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;
|
||||
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<int>(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);
|
||||
|
|
|
@ -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<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);
|
||||
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.
|
||||
|
|
|
@ -673,7 +673,7 @@ MRCOwned<id<MTLFunction>> 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<id<MTLRenderPipelineState>> 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<id<MTLComputePipelineState>> GSDeviceMTL::MakeComputePipeline(id<MTLFun
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
@ -914,269 +914,262 @@ bool GSDeviceMTL::Create()
|
|||
m_features.cas_sharpening = true;
|
||||
m_features.test_and_sample_depth = true;
|
||||
|
||||
try
|
||||
// Init metal stuff
|
||||
m_fn_constants = MRCTransfer([MTLFunctionConstantValues new]);
|
||||
setFnConstantB(m_fn_constants, m_dev.features.framebuffer_fetch, GSMTLConstantIndex_FRAMEBUFFER_FETCH);
|
||||
|
||||
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<MTLCommandBuffer> initCommands = [m_queue commandBuffer];
|
||||
id<MTLBlitCommandEncoder> 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<MTLCommandBuffer> initCommands = [m_queue commandBuffer];
|
||||
id<MTLBlitCommandEncoder> 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<u32>(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<ShaderConvert>(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<PresentShader>(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<u32>(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<ShaderConvert>(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<PresentShader>(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;
|
||||
}}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<u32>(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) \
|
||||
|
|
|
@ -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.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);
|
||||
|
|
Loading…
Reference in New Issue