mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
GS: Better handle imgui texture creation hazards.
This commit is contained in:
@@ -502,68 +502,67 @@ void GSDevice::UpdateImGuiTextures()
|
||||
case ImTextureStatus_Destroyed:
|
||||
continue;
|
||||
case ImTextureStatus_WantCreate:
|
||||
{
|
||||
GSTexture* gs_tex = g_gs_device->CreateTexture(im_tex->Width, im_tex->Height, 1, GSTexture::Format::Color);
|
||||
if (!gs_tex)
|
||||
pxFailRel("Failed to create ImGui texture");
|
||||
|
||||
im_tex->SetTexID(reinterpret_cast<ImTextureID>(gs_tex->GetNativeHandle()));
|
||||
im_tex->BackendUserData = gs_tex;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case ImTextureStatus_WantUpdates:
|
||||
{
|
||||
// If we fell through from WantCreate, then we are uploading the full size
|
||||
// Otherwise, we are just updating the specified region
|
||||
// clange-format off
|
||||
const int upload_x = (im_tex->Status == ImTextureStatus_WantCreate) ? 0 : im_tex->UpdateRect.x;
|
||||
const int upload_y = (im_tex->Status == ImTextureStatus_WantCreate) ? 0 : im_tex->UpdateRect.y;
|
||||
const int upload_w = (im_tex->Status == ImTextureStatus_WantCreate) ? im_tex->Width : im_tex->UpdateRect.w;
|
||||
const int upload_h = (im_tex->Status == ImTextureStatus_WantCreate) ? im_tex->Height : im_tex->UpdateRect.h;
|
||||
const int upload_pitch = upload_w * im_tex->BytesPerPixel;
|
||||
// clange-format on
|
||||
|
||||
const GSVector4i rect{
|
||||
upload_x,
|
||||
upload_y,
|
||||
upload_x + upload_w,
|
||||
upload_y + upload_h,
|
||||
};
|
||||
|
||||
GSTexture* gs_tex = static_cast<GSTexture*>(im_tex->BackendUserData);
|
||||
GSTexture::GSMap map;
|
||||
if (gs_tex->Map(map, &rect))
|
||||
if (GSTexture* gs_tex = g_gs_device->CreateTexture(im_tex->Width, im_tex->Height, 1, GSTexture::Format::Color))
|
||||
{
|
||||
for (int y = 0; y < upload_h; y++)
|
||||
std::memcpy(map.bits + map.pitch * y, im_tex->GetPixelsAt(rect.x, rect.y + y), upload_pitch);
|
||||
|
||||
gs_tex->Unmap();
|
||||
im_tex->SetTexID(reinterpret_cast<ImTextureID>(gs_tex->GetNativeHandle()));
|
||||
im_tex->BackendUserData = gs_tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < upload_h; y++)
|
||||
gs_tex->Update({rect.left, rect.top + y, rect.right, rect.top + y + 1},
|
||||
im_tex->GetPixelsAt(rect.x, rect.y + y), upload_pitch);
|
||||
}
|
||||
|
||||
im_tex->Status = ImTextureStatus_OK;
|
||||
break;
|
||||
}
|
||||
case ImTextureStatus_WantDestroy:
|
||||
{
|
||||
GSTexture* gs_tex = static_cast<GSTexture*>(im_tex->BackendUserData);
|
||||
if (gs_tex == nullptr)
|
||||
pxFailRel("Failed to create ImGui texture");
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case ImTextureStatus_WantUpdates:
|
||||
if (GSTexture* gs_tex = static_cast<GSTexture*>(im_tex->BackendUserData))
|
||||
{
|
||||
// If we fell through from WantCreate, then we are uploading the full size
|
||||
// Otherwise, we are just updating the specified region
|
||||
// clange-format off
|
||||
const int upload_x = (im_tex->Status == ImTextureStatus_WantCreate) ? 0 : im_tex->UpdateRect.x;
|
||||
const int upload_y = (im_tex->Status == ImTextureStatus_WantCreate) ? 0 : im_tex->UpdateRect.y;
|
||||
const int upload_w = (im_tex->Status == ImTextureStatus_WantCreate) ? im_tex->Width : im_tex->UpdateRect.w;
|
||||
const int upload_h = (im_tex->Status == ImTextureStatus_WantCreate) ? im_tex->Height : im_tex->UpdateRect.h;
|
||||
const int upload_pitch = upload_w * im_tex->BytesPerPixel;
|
||||
// clange-format on
|
||||
|
||||
// While it's unlikely we're going to reuse the same size as imgui for rendering,
|
||||
// imgui may request a new atlas of the same size if old font sizes are evicted.
|
||||
Recycle(gs_tex);
|
||||
const GSVector4i rect{
|
||||
upload_x,
|
||||
upload_y,
|
||||
upload_x + upload_w,
|
||||
upload_y + upload_h,
|
||||
};
|
||||
|
||||
im_tex->SetTexID(ImTextureID_Invalid);
|
||||
im_tex->BackendUserData = nullptr;
|
||||
im_tex->Status = ImTextureStatus_Destroyed;
|
||||
GSTexture::GSMap map;
|
||||
if (gs_tex->Map(map, &rect))
|
||||
{
|
||||
for (int y = 0; y < upload_h; y++)
|
||||
std::memcpy(map.bits + map.pitch * y, im_tex->GetPixelsAt(rect.x, rect.y + y), upload_pitch);
|
||||
|
||||
gs_tex->Unmap();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < upload_h; y++)
|
||||
gs_tex->Update({rect.left, rect.top + y, rect.right, rect.top + y + 1},
|
||||
im_tex->GetPixelsAt(rect.x, rect.y + y), upload_pitch);
|
||||
}
|
||||
|
||||
im_tex->Status = ImTextureStatus_OK;
|
||||
}
|
||||
break;
|
||||
case ImTextureStatus_WantDestroy:
|
||||
if (GSTexture* gs_tex = static_cast<GSTexture*>(im_tex->BackendUserData))
|
||||
{
|
||||
// While it's unlikely we're going to reuse the same size as imgui for rendering,
|
||||
// imgui may request a new atlas of the same size if old font sizes are evicted.
|
||||
Recycle(gs_tex);
|
||||
|
||||
im_tex->SetTexID(ImTextureID_Invalid);
|
||||
im_tex->BackendUserData = nullptr;
|
||||
im_tex->Status = ImTextureStatus_Destroyed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
pxAssert(false);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user