Get it rendering on Vulkan and D3D11 (OpenGL is bugged though)

This commit is contained in:
Henrik Rydgård 2024-10-30 19:36:54 +01:00
parent 4b66a80d2b
commit 17a7c80cb1
7 changed files with 143 additions and 32 deletions

View file

@ -132,6 +132,7 @@ public:
void DrawIndexed(int indexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt) override;
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt, Slice<ClippedDraw> draws) override;
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
@ -1378,6 +1379,31 @@ void D3D11DrawContext::DrawIndexedUP(const void *vdata, int vertexCount, const v
DrawIndexed(indexCount, 0);
}
void D3D11DrawContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt, Slice<ClippedDraw> draws) {
int vbyteSize = vertexCount * curPipeline_->input->stride;
int ibyteSize = indexCount * (ifmt == IndexFormat::U32 ? 4 : 2);
UpdateBuffer(upBuffer_, (const uint8_t *)vdata, 0, vbyteSize, Draw::UPDATE_DISCARD);
BindVertexBuffer(upBuffer_, 0);
UpdateBuffer(upIBuffer_, (const uint8_t *)idata, 0, ibyteSize, Draw::UPDATE_DISCARD);
BindIndexBuffer(upIBuffer_, 0);
// Override the index buffer format.
nextIndexBufferFormat_ = ifmt == IndexFormat::U32 ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;
ApplyCurrentState();
for (int i = 0; i < draws.size(); i++) {
D3D11_RECT rc;
rc.left = draws[i].clipx;
rc.top = draws[i].clipy;
rc.right = draws[i].clipx + draws[i].clipw;
rc.bottom = draws[i].clipy + draws[i].cliph;
context_->RSSetScissorRects(1, &rc);
context_->DrawIndexed(draws[i].indexCount, draws[i].indexOffset, 0);
}
}
uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const {
DXGI_FORMAT giFmt = dataFormatToD3D11(fmt);
if (giFmt == DXGI_FORMAT_UNKNOWN)

View file

@ -444,6 +444,7 @@ public:
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt) override;
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt, Slice<ClippedDraw> draws);
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
@ -1438,10 +1439,40 @@ void OpenGLContext::DrawIndexedUP(const void *vdata, int vertexCount, const void
memcpy(dest, idata, idataSize);
ApplySamplers();
_assert_(curPipeline_->inputLayout);
renderManager_.DrawIndexed(curPipeline_->inputLayout->inputLayout_, vbuf, voffset, ibuf, ioffset, curPipeline_->prim, 0, ifmt == IndexFormat::U32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, vertexCount);
}
void OpenGLContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt, Slice<ClippedDraw> draws) {
_assert_(curPipeline_->inputLayout != nullptr);
int stride = curPipeline_->inputLayout->stride;
uint32_t vdataSize = stride * vertexCount;
int indexSize = (ifmt == IndexFormat::U32 ? 4 : 2);
uint32_t idataSize = indexCount * indexSize;
FrameData &frameData = frameData_[renderManager_.GetCurFrame()];
GLRBuffer *vbuf;
uint32_t voffset;
uint8_t *dest = frameData.push->Allocate(vdataSize, 4, &vbuf, &voffset);
memcpy(dest, vdata, vdataSize);
GLRBuffer *ibuf;
uint32_t ioffset;
dest = frameData.push->Allocate(idataSize, 4, &ibuf, &ioffset);
memcpy(dest, idata, idataSize);
ApplySamplers();
for (auto &draw : draws) {
GLRect2D scissor;
scissor.x = draw.clipx;
scissor.y = draw.clipy;
scissor.w = draw.clipw;
scissor.h = draw.cliph;
renderManager_.SetScissor(scissor);
renderManager_.DrawIndexed(curPipeline_->inputLayout->inputLayout_, vbuf, voffset, ibuf, ioffset + draw.indexOffset * indexSize, curPipeline_->prim, 0, ifmt == IndexFormat::U32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, draw.indexCount);
}
}
void OpenGLContext::Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) {
float col[4];
Uint8x4ToFloat4(col, colorval);

View file

@ -492,6 +492,8 @@ public:
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt) override;
// Specialized for quick IMGUI drawing.
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt, Slice<ClippedDraw>) override;
void BindCurrentPipeline();
void ApplyDynamicState();
@ -1555,6 +1557,43 @@ void VKContext::DrawIndexedUP(const void *vdata, int vertexCount, const void *id
renderManager_.DrawIndexed(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, indexCount, 1, ifmt == IndexFormat::U32 ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
}
void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt, Slice<ClippedDraw> draws) {
_dbg_assert_(vertexCount >= 0);
_dbg_assert_(indexCount >= 0);
if (vertexCount <= 0 || indexCount <= 0 || draws.is_empty()) {
return;
}
VkBuffer vulkanVbuf, vulkanIbuf, vulkanUBObuf;
size_t vdataSize = vertexCount * curPipeline_->stride;
uint32_t vbBindOffset;
uint8_t *vdataPtr = push_->Allocate(vdataSize, 4, &vulkanVbuf, &vbBindOffset);
_assert_(vdataPtr != nullptr);
memcpy(vdataPtr, vdata, vdataSize);
int indexSize = (ifmt == IndexFormat::U32 ? 4 : 2);
size_t idataSize = indexCount * indexSize;
uint32_t ibBindOffset;
uint8_t *idataPtr = push_->Allocate(idataSize, 4, &vulkanIbuf, &ibBindOffset);
_assert_(idataPtr != nullptr);
memcpy(idataPtr, idata, idataSize);
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
BindCurrentPipeline();
ApplyDynamicState();
int descSetIndex;
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
for (auto &draw : draws) {
BindDescriptors(vulkanUBObuf, descriptors);
renderManager_.SetScissor(draw.clipx, draw.clipy, draw.clipw, draw.cliph);
renderManager_.DrawIndexed(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf,
(int)ibBindOffset + draw.indexOffset * indexSize, draw.indexCount, 1, ifmt == IndexFormat::U32 ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16);
}
}
void VKContext::BindCurrentPipeline() {
renderManager_.BindPipeline(curPipeline_->pipeline, curPipeline_->flags, pipelineLayout_);
}

View file

@ -699,6 +699,15 @@ struct BackendState {
bool valid;
};
struct ClippedDraw {
int indexOffset;
int indexCount;
s16 clipx;
s16 clipy;
s16 clipw;
s16 cliph;
};
class DrawContext {
public:
virtual ~DrawContext() = default;
@ -834,6 +843,7 @@ public:
virtual void DrawIndexed(int vertexCount, int offset) = 0; // Always 16-bit indices.
virtual void DrawUP(const void *vdata, int vertexCount) = 0;
virtual void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt) = 0; // Supports 32-bit indices, for IMGUI use.
virtual void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, IndexFormat ifmt, Slice<ClippedDraw> draws) {}
// Frame management (for the purposes of sync and resource management, necessary with modern APIs). Default implementations here.
virtual void BeginFrame(DebugFlags debugFlags) = 0;

View file

@ -1590,6 +1590,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
}
ImGui_ImplPlatform_NewFrame();
ImGui_ImplThin3d_NewFrame(draw, ui_draw2d.GetDrawMatrix());
// Draw imgui on top
ImGui::NewFrame();

View file

@ -5,12 +5,14 @@
#include <cstdio>
#include "Common/System/Display.h"
#include "Common/Math/lin/matrix4x4.h"
// Forward Declarations
bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw);
void ImGui_ImplThin3d_DestroyDeviceObjects(Draw::DrawContext *draw);
Lin::Matrix4x4 g_drawMatrix;
struct ImGui_ImplThin3d_Data {
Draw::SamplerState *fontSampler = nullptr;
Draw::Texture *fontImage = nullptr;
@ -33,10 +35,10 @@ void ImGui_ImplPlatform_NewFrame() {
static void ImGui_ImplThin3d_SetupRenderState(Draw::DrawContext *draw, ImDrawData* draw_data, Draw::Pipeline *pipeline, int fb_width, int fb_height) {
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
// Bind pipeline:
{
draw->BindPipeline(pipeline);
}
// Bind pipeline and texture
draw->BindPipeline(pipeline);
draw->BindTexture(0, bd->fontImage);
draw->BindSamplerStates(0, 1, &bd->fontSampler);
// Setup viewport:
{
@ -52,16 +54,14 @@ static void ImGui_ImplThin3d_SetupRenderState(Draw::DrawContext *draw, ImDrawDat
// Setup scale and translation:
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
// We currently ignore DisplayPos.
{
float scale[2];
scale[0] = 2.0f / draw_data->DisplaySize.x;
scale[1] = 2.0f / draw_data->DisplaySize.y;
float translate[2];
translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0];
translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1];
Lin::Matrix4x4 mtx = ComputeOrthoMatrix(draw_data->DisplaySize.x, draw_data->DisplaySize.y, draw->GetDeviceCaps().coordConvention);
// vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale);
// vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate);
Draw::VsTexColUB ub{};
memcpy(ub.WorldViewProj, mtx.getReadPtr(), sizeof(Lin::Matrix4x4));
ub.saturation = 1.0f;
draw->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
}
}
@ -82,9 +82,13 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
const Draw::IndexFormat idxFormat = sizeof(ImDrawIdx) == 2 ? Draw::IndexFormat::U16 : Draw::IndexFormat::U32;
std::vector<Draw::ClippedDraw> draws;
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++) {
const ImDrawList* cmd_list = draw_data->CmdLists[n];
draws.clear();
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != nullptr) {
@ -108,17 +112,17 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle
draw->SetScissorRect(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
draw->BindTexture(0, (Draw::Texture *)pcmd->TextureId);
// Draw
// vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
Draw::ClippedDraw draw;
draw.clipx = clip_min.x;
draw.clipy = clip_min.y;
draw.clipw = clip_max.x - clip_min.x;
draw.cliph = clip_max.y - clip_min.y;
draw.indexCount = pcmd->ElemCount;
draw.indexOffset = pcmd->IdxOffset;
draws.push_back(draw);
}
}
// global_idx_offset += cmd_list->IdxBuffer.Size;
// global_vtx_offset += cmd_list->VtxBuffer.Size;
draw->DrawIndexedClippedBatchUP(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.size(), cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.size(), idxFormat, draws);
}
draw->SetScissorRect(0, 0, fb_width, fb_height);
@ -159,8 +163,7 @@ bool ImGui_ImplThin3d_CreateFontsTexture(Draw::DrawContext *draw) {
}
// You probably never need to call this, as it is called by ImGui_ImplThin3d_CreateFontsTexture() and ImGui_ImplThin3d_Shutdown().
void ImGui_ImplThin3d_DestroyFontsTexture(Draw::DrawContext *draw)
{
void ImGui_ImplThin3d_DestroyFontsTexture(Draw::DrawContext *draw) {
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
if (bd->fontImage) {
@ -209,8 +212,7 @@ static void ImGui_ImplThin3d_CreatePipeline(Draw::DrawContext *draw) {
bd->pipeline = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline");
}
bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw)
{
bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
if (!bd->fontSampler) {
@ -237,6 +239,8 @@ void ImGui_ImplThin3d_DestroyDeviceObjects(Draw::DrawContext *draw) {
ImGui_ImplThin3d_DestroyFontsTexture(draw);
bd->pipeline->Release();
bd->pipeline = nullptr;
bd->fontSampler->Release();
bd->fontSampler = nullptr;
}
bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw) {
@ -253,8 +257,7 @@ bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw) {
return true;
}
void ImGui_ImplThin3d_Shutdown(Draw::DrawContext *draw)
{
void ImGui_ImplThin3d_Shutdown(Draw::DrawContext *draw) {
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
@ -266,12 +269,12 @@ void ImGui_ImplThin3d_Shutdown(Draw::DrawContext *draw)
IM_DELETE(bd);
}
void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw)
{
void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatrix) {
ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData();
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplThin3d_Init()?");
if (!bd->fontImage)
ImGui_ImplThin3d_CreateFontsTexture(draw);
g_drawMatrix = drawMatrix;
}
// Register a texture. No-op.

View file

@ -31,11 +31,12 @@
#include "imgui.h" // IMGUI_IMPL_API
#include "Common/GPU/thin3d.h"
#include "Common/Math/lin/matrix4x4.h"
// Called by user code
IMGUI_IMPL_API bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw);
IMGUI_IMPL_API void ImGui_ImplThin3d_Shutdown(Draw::DrawContext *draw);
IMGUI_IMPL_API void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw);
IMGUI_IMPL_API void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatrix);
IMGUI_IMPL_API void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *draw);
IMGUI_IMPL_API bool ImGui_ImplThin3d_CreateFontsTexture(Draw::DrawContext *draw);
IMGUI_IMPL_API void ImGui_ImplThin3d_DestroyFontsTexture(Draw::DrawContext *draw);