renderer_vulkan: Surface fills and dual screen rendering working
This commit is contained in:
@ -39,6 +39,8 @@ struct Rectangle {
|
||||
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
|
||||
static_cast<T>(top + GetHeight() * s)};
|
||||
}
|
||||
|
||||
auto operator <=> (const Rectangle<T>& other) const = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -280,7 +280,7 @@ void RendererVulkan::CreateVulkanObjects() {
|
||||
|
||||
// Generate VBO handle for drawing
|
||||
VKBuffer::Info vertex_info{
|
||||
.size = sizeof(ScreenRectVertex) * 4,
|
||||
.size = sizeof(ScreenRectVertex) * 10,
|
||||
.properties = vk::MemoryPropertyFlagBits::eDeviceLocal,
|
||||
.usage = vk::BufferUsageFlagBits::eVertexBuffer |
|
||||
vk::BufferUsageFlagBits::eTransferDst
|
||||
@ -340,19 +340,23 @@ void RendererVulkan::ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::
|
||||
* Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD
|
||||
* rotation.
|
||||
*/
|
||||
void RendererVulkan::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y,
|
||||
float w, float h) {
|
||||
void RendererVulkan::DrawSingleScreenRotated(u32 screen_id, float x, float y, float w, float h) {
|
||||
auto& screen_info = screen_infos[screen_id];
|
||||
const auto& texcoords = screen_info.display_texcoords;
|
||||
|
||||
u32 size = sizeof(ScreenRectVertex) * 4;
|
||||
auto [ptr, offset, invalidate] = vertex_buffer.Map(size);
|
||||
|
||||
const std::array vertices{
|
||||
ScreenRectVertex(x, y, texcoords.bottom, texcoords.left),
|
||||
ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right),
|
||||
ScreenRectVertex(x, y + h, texcoords.top, texcoords.left),
|
||||
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right),
|
||||
ScreenRectVertex(x, y, texcoords.bottom, texcoords.left, screen_id),
|
||||
ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right, screen_id),
|
||||
ScreenRectVertex(x, y + h, texcoords.top, texcoords.left, screen_id),
|
||||
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right, screen_id),
|
||||
};
|
||||
|
||||
auto data = std::as_bytes(std::span(vertices));
|
||||
vertex_buffer.Upload(data, 0);
|
||||
std::memcpy(ptr, vertices.data(), size);
|
||||
vertex_buffer.Commit(size, vk::AccessFlagBits::eVertexAttributeRead,
|
||||
vk::PipelineStageFlagBits::eVertexInput);
|
||||
|
||||
// As this is the "DrawSingleScreenRotated" function, the output resolution dimensions have been
|
||||
// swapped. If a non-rotated draw-screen function were to be added for book-mode games, those
|
||||
@ -365,34 +369,32 @@ void RendererVulkan::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa
|
||||
1.0f / (height * scale_factor)};
|
||||
draw_info.o_resolution = glm::vec4{h, w, 1.0f / h, 1.0f / w};
|
||||
|
||||
auto& image = swapchain->GetCurrentImage();
|
||||
auto& state = VulkanState::Get();
|
||||
|
||||
state.BeginRendering(image, std::nullopt, false, clear_color, vk::AttachmentLoadOp::eClear);
|
||||
state.SetPresentData(draw_info);
|
||||
state.SetPresentTexture(*screen_info.display_texture);
|
||||
state.ApplyPresentState();
|
||||
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
|
||||
vk::DeviceSize offset = 0;
|
||||
|
||||
cmdbuffer.bindVertexBuffers(0, 1, &vertex_buffer.GetBuffer(), &offset);
|
||||
cmdbuffer.draw(4, 1, 0, 0);
|
||||
cmdbuffer.bindVertexBuffers(0, vertex_buffer.GetBuffer(), {0});
|
||||
cmdbuffer.draw(4, 1, offset / sizeof(ScreenRectVertex), 0);
|
||||
}
|
||||
|
||||
void RendererVulkan::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w,
|
||||
float h) {
|
||||
void RendererVulkan::DrawSingleScreen(u32 screen_id, float x, float y, float w, float h) {
|
||||
auto& screen_info = screen_infos[screen_id];
|
||||
const auto& texcoords = screen_info.display_texcoords;
|
||||
|
||||
u32 size = sizeof(ScreenRectVertex) * 4;
|
||||
auto [ptr, offset, invalidate] = vertex_buffer.Map(size);
|
||||
|
||||
const std::array vertices{
|
||||
ScreenRectVertex(x, y, texcoords.bottom, texcoords.right),
|
||||
ScreenRectVertex(x + w, y, texcoords.top, texcoords.right),
|
||||
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left),
|
||||
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left),
|
||||
ScreenRectVertex(x, y, texcoords.bottom, texcoords.right, screen_id),
|
||||
ScreenRectVertex(x + w, y, texcoords.top, texcoords.right, screen_id),
|
||||
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left, screen_id),
|
||||
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left, screen_id),
|
||||
};
|
||||
|
||||
auto data = std::as_bytes(std::span(vertices));
|
||||
vertex_buffer.Upload(data, 0);
|
||||
std::memcpy(ptr, vertices.data(), size);
|
||||
vertex_buffer.Commit(size, vk::AccessFlagBits::eVertexAttributeRead,
|
||||
vk::PipelineStageFlagBits::eVertexInput);
|
||||
|
||||
const u16 scale_factor = VideoCore::GetResolutionScaleFactor();
|
||||
auto [width, height] = screen_info.texture.GetArea().extent;
|
||||
@ -403,17 +405,13 @@ void RendererVulkan::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl
|
||||
1.0f / (height * scale_factor)};
|
||||
draw_info.o_resolution = glm::vec4{h, w, 1.0f / h, 1.0f / w};
|
||||
|
||||
auto& image = swapchain->GetCurrentImage();
|
||||
auto& state = VulkanState::Get();
|
||||
|
||||
state.BeginRendering(image, std::nullopt, false, clear_color, vk::AttachmentLoadOp::eClear);
|
||||
state.SetPresentData(draw_info);
|
||||
state.SetPresentTexture(*screen_info.display_texture);
|
||||
state.ApplyPresentState();
|
||||
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
|
||||
|
||||
cmdbuffer.bindVertexBuffers(0, vertex_buffer.GetBuffer(), {0});
|
||||
cmdbuffer.draw(4, 1, 0, 0);
|
||||
cmdbuffer.draw(4, 1, offset / sizeof(ScreenRectVertex), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -423,7 +421,8 @@ void RendererVulkan::DrawSingleScreen(const ScreenInfo& screen_info, float x, fl
|
||||
void RendererVulkan::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l,
|
||||
const ScreenInfo& screen_info_r, float x,
|
||||
float y, float w, float h) {
|
||||
DrawSingleScreenRotated(screen_info_l, x, y, w, h);
|
||||
ASSERT(false);
|
||||
//DrawSingleScreenRotated(screen_info_l, x, y, w, h);
|
||||
/*const auto& texcoords = screen_info_l.display_texcoords;
|
||||
|
||||
const std::array<ScreenRectVertex, 4> vertices = {{
|
||||
@ -460,7 +459,8 @@ void RendererVulkan::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info
|
||||
void RendererVulkan::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
|
||||
const ScreenInfo& screen_info_r, float x, float y,
|
||||
float w, float h) {
|
||||
DrawSingleScreen(screen_info_l, x, y, w, h);
|
||||
ASSERT(false);
|
||||
//DrawSingleScreen(screen_info_l, x, y, w, h);
|
||||
/*const auto& texcoords = screen_info_l.display_texcoords;
|
||||
|
||||
const std::array<ScreenRectVertex, 4> vertices = {{
|
||||
@ -518,8 +518,9 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
|
||||
const auto& bottom_screen = layout.bottom_screen;
|
||||
|
||||
// Set projection matrix
|
||||
draw_info.modelview = MakeOrthographicMatrix((float)layout.width, (float)layout.height, flipped);
|
||||
|
||||
draw_info.modelview = glm::transpose(glm::ortho(0.f, static_cast<float>(layout.width),
|
||||
static_cast<float>(layout.height), 0.0f,
|
||||
0.f, 1.f));
|
||||
const bool stereo_single_screen = false
|
||||
/* Settings::values.render_3d == Settings::StereoRenderOption::Anaglyph ||
|
||||
Settings::values.render_3d == Settings::StereoRenderOption::Interlaced ||
|
||||
@ -530,28 +531,37 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
|
||||
//glUniform1i(uniform_color_texture_r, 1);
|
||||
}
|
||||
|
||||
auto& image = swapchain->GetCurrentImage();
|
||||
auto& state = VulkanState::Get();
|
||||
|
||||
state.BeginRendering(image, std::nullopt, false, clear_color, vk::AttachmentLoadOp::eClear);
|
||||
state.SetPresentTextures(screen_infos[0].display_texture->GetView(),
|
||||
screen_infos[1].display_texture->GetView(),
|
||||
screen_infos[2].display_texture->GetView());
|
||||
state.ApplyPresentState();
|
||||
|
||||
draw_info.layer = 0;
|
||||
if (layout.top_screen_enabled) {
|
||||
if (layout.is_rotated) {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left,
|
||||
(float)top_screen.top, (float)top_screen.GetWidth(),
|
||||
(float)top_screen.GetHeight());
|
||||
DrawSingleScreenRotated(0, top_screen.left,
|
||||
top_screen.top, top_screen.GetWidth(),
|
||||
top_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left / 2,
|
||||
DrawSingleScreenRotated(0, (float)top_screen.left / 2,
|
||||
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
|
||||
(float)top_screen.GetHeight());
|
||||
draw_info.layer = 1;
|
||||
DrawSingleScreenRotated(screen_infos[1],
|
||||
DrawSingleScreenRotated(1,
|
||||
((float)top_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
|
||||
(float)top_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
|
||||
DrawSingleScreenRotated(screen_infos[0], layout.top_screen.left,
|
||||
DrawSingleScreenRotated(0, layout.top_screen.left,
|
||||
layout.top_screen.top, layout.top_screen.GetWidth(),
|
||||
layout.top_screen.GetHeight());
|
||||
draw_info.layer = 1;
|
||||
DrawSingleScreenRotated(screen_infos[1],
|
||||
DrawSingleScreenRotated(1,
|
||||
layout.cardboard.top_screen_right_eye +
|
||||
((float)layout.width / 2),
|
||||
layout.top_screen.top, layout.top_screen.GetWidth(),
|
||||
@ -563,21 +573,21 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
|
||||
}
|
||||
} else {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreen(screen_infos[0], (float)top_screen.left, (float)top_screen.top,
|
||||
DrawSingleScreen(0, (float)top_screen.left, (float)top_screen.top,
|
||||
(float)top_screen.GetWidth(), (float)top_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreen(screen_infos[0], (float)top_screen.left / 2, (float)top_screen.top,
|
||||
DrawSingleScreen(0, (float)top_screen.left / 2, (float)top_screen.top,
|
||||
(float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight());
|
||||
draw_info.layer = 1;
|
||||
DrawSingleScreen(screen_infos[1],
|
||||
DrawSingleScreen(1,
|
||||
((float)top_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
|
||||
(float)top_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
|
||||
DrawSingleScreen(screen_infos[0], layout.top_screen.left, layout.top_screen.top,
|
||||
DrawSingleScreen(0, layout.top_screen.left, layout.top_screen.top,
|
||||
layout.top_screen.GetWidth(), layout.top_screen.GetHeight());
|
||||
draw_info.layer = 1;
|
||||
DrawSingleScreen(screen_infos[1],
|
||||
DrawSingleScreen(1,
|
||||
layout.cardboard.top_screen_right_eye + ((float)layout.width / 2),
|
||||
layout.top_screen.top, layout.top_screen.GetWidth(),
|
||||
layout.top_screen.GetHeight());
|
||||
@ -588,28 +598,29 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draw_info.layer = 0;
|
||||
if (/*layout.bottom_screen_enabled*/false) {
|
||||
if (layout.bottom_screen_enabled) {
|
||||
if (layout.is_rotated) {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left,
|
||||
DrawSingleScreenRotated(2, (float)bottom_screen.left,
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth(),
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreenRotated(
|
||||
screen_infos[2], (float)bottom_screen.left / 2, (float)bottom_screen.top,
|
||||
2, (float)bottom_screen.left / 2, (float)bottom_screen.top,
|
||||
(float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetHeight());
|
||||
draw_info.layer = 1;
|
||||
DrawSingleScreenRotated(
|
||||
screen_infos[2], ((float)bottom_screen.left / 2) + ((float)layout.width / 2),
|
||||
2, ((float)bottom_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
|
||||
DrawSingleScreenRotated(screen_infos[2], layout.bottom_screen.left,
|
||||
DrawSingleScreenRotated(2, layout.bottom_screen.left,
|
||||
layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
|
||||
layout.bottom_screen.GetHeight());
|
||||
draw_info.layer = 1;
|
||||
DrawSingleScreenRotated(screen_infos[2],
|
||||
DrawSingleScreenRotated(2,
|
||||
layout.cardboard.bottom_screen_right_eye +
|
||||
((float)layout.width / 2),
|
||||
layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
|
||||
@ -622,24 +633,24 @@ void RendererVulkan::DrawScreens(const Layout::FramebufferLayout& layout, bool f
|
||||
}
|
||||
} else {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreen(screen_infos[2], (float)bottom_screen.left,
|
||||
DrawSingleScreen(2, (float)bottom_screen.left,
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth(),
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreen(screen_infos[2], (float)bottom_screen.left / 2,
|
||||
DrawSingleScreen(2, (float)bottom_screen.left / 2,
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
|
||||
(float)bottom_screen.GetHeight());
|
||||
draw_info.layer = 1;
|
||||
DrawSingleScreen(screen_infos[2],
|
||||
DrawSingleScreen(2,
|
||||
((float)bottom_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
|
||||
DrawSingleScreen(screen_infos[2], layout.bottom_screen.left,
|
||||
DrawSingleScreen(2, layout.bottom_screen.left,
|
||||
layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
|
||||
layout.bottom_screen.GetHeight());
|
||||
draw_info.layer = 1;
|
||||
DrawSingleScreen(screen_infos[2],
|
||||
DrawSingleScreen(2,
|
||||
layout.cardboard.bottom_screen_right_eye +
|
||||
((float)layout.width / 2),
|
||||
layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
|
||||
|
@ -52,8 +52,8 @@ private:
|
||||
void ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::Regs::FramebufferConfig& framebuffer);
|
||||
|
||||
void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped);
|
||||
void DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h);
|
||||
void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h);
|
||||
void DrawSingleScreenRotated(u32 screen_id, float x, float y, float w, float h);
|
||||
void DrawSingleScreen(u32 screen_id, float x, float y, float w, float h);
|
||||
void DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l,
|
||||
const ScreenInfo& screen_info_r, float x, float y, float w, float h);
|
||||
void DrawSingleScreenStereo(const ScreenInfo& screen_info_l, const ScreenInfo& screen_info_r,
|
||||
@ -70,7 +70,7 @@ private:
|
||||
private:
|
||||
// Vulkan state
|
||||
DrawInfo draw_info{};
|
||||
VKBuffer vertex_buffer;
|
||||
StreamBuffer vertex_buffer;
|
||||
vk::ClearColorValue clear_color{};
|
||||
|
||||
/// Display information for top and bottom screens respectively
|
||||
|
@ -133,7 +133,7 @@ std::tuple<u8*, u32, bool> StreamBuffer::Map(u32 size, u32 alignment) {
|
||||
auto [staging_ptr, staging_offset] = g_vk_task_scheduler->RequestStaging(size);
|
||||
mapped_chunk = vk::BufferCopy{staging_offset, buffer_pos, size};
|
||||
|
||||
return std::make_tuple(staging_ptr + buffer_pos, buffer_pos, invalidate);
|
||||
return std::make_tuple(staging_ptr, buffer_pos, invalidate);
|
||||
}
|
||||
|
||||
void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block,
|
||||
@ -148,7 +148,7 @@ void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block,
|
||||
vk::BufferMemoryBarrier barrier{
|
||||
vk::AccessFlagBits::eTransferWrite, access_to_block,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED,
|
||||
buffer, mapped_chunk.srcOffset, mapped_chunk.size
|
||||
buffer, mapped_chunk.dstOffset, mapped_chunk.size
|
||||
};
|
||||
|
||||
// Add a pipeline barrier for the region modified
|
||||
@ -158,9 +158,6 @@ void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block,
|
||||
|
||||
buffer_pos += size;
|
||||
}
|
||||
else {
|
||||
printf("f");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -288,6 +288,55 @@ static bool BlitTextures(const Surface& src_surface, const Common::Rectangle<u32
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool FillSurface(const Surface& surface, std::array<u8, 4> fill_buffer,
|
||||
Common::Rectangle<u32> rect) {
|
||||
if (surface->GetScaledRect() != rect) {
|
||||
// TODO: use vkCmdClearAttachments to clear subrects
|
||||
LOG_ERROR(Render_Vulkan, "Partial surface fills not implemented");
|
||||
}
|
||||
|
||||
vk::ImageSubresourceRange image_range{{}, 0, 1, 0, 1};
|
||||
switch (surface->type) {
|
||||
case SurfaceParams::SurfaceType::Color:
|
||||
case SurfaceParams::SurfaceType::Texture:
|
||||
image_range.aspectMask = vk::ImageAspectFlagBits::eColor;
|
||||
break;
|
||||
case SurfaceParams::SurfaceType::Depth:
|
||||
image_range.aspectMask = vk::ImageAspectFlagBits::eDepth;
|
||||
break;
|
||||
case SurfaceParams::SurfaceType::DepthStencil:
|
||||
image_range.aspectMask =
|
||||
vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
|
||||
switch (surface->type) {
|
||||
case SurfaceParams::SurfaceType::Color:
|
||||
case SurfaceParams::SurfaceType::Texture: {
|
||||
Pica::Texture::TextureInfo tex_info{};
|
||||
tex_info.format = static_cast<Pica::TexturingRegs::TextureFormat>(surface->pixel_format);
|
||||
|
||||
auto color_vec = Pica::Texture::LookupTexture(fill_buffer.data(), 0, 0, tex_info) / 255.0f;
|
||||
const std::array color{color_vec.x, color_vec.y, color_vec.z, color_vec.w};
|
||||
|
||||
auto& texture = surface->texture;
|
||||
texture.Transition(cmdbuffer, vk::ImageLayout::eTransferDstOptimal);
|
||||
|
||||
cmdbuffer.clearColorImage(texture.GetHandle(), vk::ImageLayout::eTransferDstOptimal,
|
||||
color, image_range);
|
||||
|
||||
texture.Transition(cmdbuffer, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(Render_Vulkan, "non-color fills not implemented");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static vk::Rect2D FromRect(Common::Rectangle<u32> rect) {
|
||||
vk::Offset2D offset{static_cast<s32>(rect.left), static_cast<s32>(rect.bottom)};
|
||||
vk::Extent2D extent{rect.GetWidth(), rect.GetHeight()};
|
||||
@ -412,7 +461,16 @@ void RasterizerCacheVulkan::CopySurface(const Surface& src_surface, const Surfac
|
||||
|
||||
// This is only called when CanCopy is true, no need to run checks here
|
||||
if (src_surface->type == SurfaceType::Fill) {
|
||||
// NO-OP Vulkan does not allow easy clearing for arbitary textures with rectangle
|
||||
// FillSurface needs a 4 bytes buffer
|
||||
const u32 fill_offset =
|
||||
(boost::icl::first(copy_interval) - src_surface->addr) % src_surface->fill_size;
|
||||
std::array<u8, 4> fill_buffer;
|
||||
|
||||
u32 fill_buff_pos = fill_offset;
|
||||
for (int i : {0, 1, 2, 3})
|
||||
fill_buffer[i] = src_surface->fill_data[fill_buff_pos++ % src_surface->fill_size];
|
||||
|
||||
FillSurface(dst_surface, fill_buffer, dst_surface->GetScaledSubRect(subrect_params));
|
||||
return;
|
||||
}
|
||||
if (src_surface->CanSubRect(subrect_params)) {
|
||||
|
@ -33,37 +33,30 @@ using VSOutputAttributes = RasterizerRegs::VSOutputAttributes;
|
||||
namespace Vulkan {
|
||||
|
||||
static const char present_vertex_shader_source[] = R"(
|
||||
#version 450
|
||||
#version 450 core
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
layout (location = 0) in vec2 vert_position;
|
||||
layout (location = 1) in vec2 vert_tex_coord;
|
||||
layout (location = 0) out vec2 frag_tex_coord;
|
||||
layout (location = 1) in vec3 vert_tex_coord;
|
||||
layout (location = 0) out vec3 frag_tex_coord;
|
||||
|
||||
// This is a truncated 3x3 matrix for 2D transformations:
|
||||
// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
|
||||
// The third column performs translation.
|
||||
// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
|
||||
// implicitly be [0, 0, 1]
|
||||
layout (push_constant) uniform DrawInfo {
|
||||
mat3x2 modelview_matrix;
|
||||
mat4 modelview_matrix;
|
||||
vec4 i_resolution;
|
||||
vec4 o_resolution;
|
||||
int layer;
|
||||
};
|
||||
|
||||
void main() {
|
||||
// Multiply input position by the rotscale part of the matrix and then manually translate by
|
||||
// the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
|
||||
// to `vec3(vert_position.xy, 1.0)`
|
||||
gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
|
||||
vec4 position = vec4(vert_position, 0.0, 1.0) * modelview_matrix;
|
||||
gl_Position = vec4(position.x, -position.y, 0.0, 1.0);
|
||||
frag_tex_coord = vert_tex_coord;
|
||||
}
|
||||
)";
|
||||
|
||||
static const char present_fragment_shader_source[] = R"(
|
||||
#version 450
|
||||
#version 450 core
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
layout (location = 0) in vec2 frag_tex_coord;
|
||||
layout (location = 0) in vec3 frag_tex_coord;
|
||||
layout (location = 0) out vec4 color;
|
||||
|
||||
layout (push_constant) uniform DrawInfo {
|
||||
@ -73,10 +66,11 @@ layout (push_constant) uniform DrawInfo {
|
||||
int layer;
|
||||
};
|
||||
|
||||
layout (set = 0, binding = 0) uniform sampler2D color_texture;
|
||||
layout (set = 0, binding = 0) uniform sampler2D screen_textures[3];
|
||||
|
||||
void main() {
|
||||
color = texture(color_texture, frag_tex_coord);
|
||||
color = texture(screen_textures[int(frag_tex_coord.z)], frag_tex_coord.xy);
|
||||
//color = vec4(0.5, 0.0, 0.5, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
|
@ -84,25 +84,26 @@ struct HardwareVertex : public VertexBase {
|
||||
|
||||
struct ScreenRectVertexBase {
|
||||
ScreenRectVertexBase() = default;
|
||||
ScreenRectVertexBase(float x, float y, float u, float v) {
|
||||
ScreenRectVertexBase(float x, float y, float u, float v, float s) {
|
||||
position.x = x;
|
||||
position.y = y;
|
||||
tex_coord.x = u;
|
||||
tex_coord.y = v;
|
||||
tex_coord.z = s;
|
||||
}
|
||||
|
||||
glm::vec2 position;
|
||||
glm::vec2 tex_coord;
|
||||
glm::vec3 tex_coord;
|
||||
};
|
||||
|
||||
struct ScreenRectVertex : public ScreenRectVertexBase {
|
||||
ScreenRectVertex() = default;
|
||||
ScreenRectVertex(float x, float y, float u, float v) : ScreenRectVertexBase(x, y, u, v) {};
|
||||
ScreenRectVertex(float x, float y, float u, float v, float s) : ScreenRectVertexBase(x, y, u, v, s) {};
|
||||
static constexpr auto binding_desc = vk::VertexInputBindingDescription(0, sizeof(ScreenRectVertexBase));
|
||||
static constexpr std::array<vk::VertexInputAttributeDescription, 2> attribute_desc =
|
||||
{
|
||||
vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32Sfloat, offsetof(ScreenRectVertexBase, position)),
|
||||
vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32Sfloat, offsetof(ScreenRectVertexBase, tex_coord)),
|
||||
vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32B32Sfloat, offsetof(ScreenRectVertexBase, tex_coord)),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -25,43 +25,56 @@ auto IsStencil = [](vk::Format format) -> bool {
|
||||
};
|
||||
};
|
||||
|
||||
void DescriptorUpdater::Reset() {
|
||||
write_count = 0;
|
||||
buffer_count = 0;
|
||||
image_count = 0;
|
||||
}
|
||||
|
||||
void DescriptorUpdater::Update() {
|
||||
assert(update_count > 0);
|
||||
assert(write_count > 0);
|
||||
|
||||
auto device = g_vk_instace->GetDevice();
|
||||
device.updateDescriptorSets(update_count, writes.data(), 0, nullptr);
|
||||
device.updateDescriptorSets(write_count, writes.data(), 0, nullptr);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void DescriptorUpdater::PushTextureArrayUpdate(vk::DescriptorSet set, u32 binding, vk::Sampler sampler,
|
||||
std::span<vk::ImageView> views) {
|
||||
ASSERT(image_count < MAX_UPDATES);
|
||||
|
||||
u32 start = image_count;
|
||||
for (auto& view : views) {
|
||||
image_infos[image_count++] = {sampler, view, vk::ImageLayout::eShaderReadOnlyOptimal};
|
||||
}
|
||||
|
||||
writes[write_count++] = vk::WriteDescriptorSet{set, binding, 0, static_cast<u32>(views.size()),
|
||||
vk::DescriptorType::eCombinedImageSampler,
|
||||
image_infos.data() + start};
|
||||
}
|
||||
|
||||
void DescriptorUpdater::PushCombinedImageSamplerUpdate(vk::DescriptorSet set, u32 binding,
|
||||
vk::Sampler sampler, vk::ImageView view) {
|
||||
assert(update_count < MAX_DESCRIPTORS);
|
||||
ASSERT(image_count < MAX_UPDATES);
|
||||
|
||||
auto& info = update_queue[update_count];
|
||||
info.image_info = vk::DescriptorImageInfo{sampler, view, vk::ImageLayout::eShaderReadOnlyOptimal};
|
||||
image_infos[image_count] = {sampler, view, vk::ImageLayout::eShaderReadOnlyOptimal};
|
||||
|
||||
writes[update_count++] = vk::WriteDescriptorSet{
|
||||
set, binding, 0, 1,
|
||||
vk::DescriptorType::eCombinedImageSampler,
|
||||
&info.image_info
|
||||
};
|
||||
writes[write_count++] = vk::WriteDescriptorSet{set, binding, 0, 1,
|
||||
vk::DescriptorType::eCombinedImageSampler,
|
||||
&image_infos[image_count++]};
|
||||
}
|
||||
|
||||
void DescriptorUpdater::PushBufferUpdate(vk::DescriptorSet set, u32 binding,
|
||||
vk::DescriptorType buffer_type, u32 offset, u32 size,
|
||||
vk::Buffer buffer, const vk::BufferView& view) {
|
||||
assert(update_count < MAX_DESCRIPTORS);
|
||||
ASSERT(buffer_count < MAX_UPDATES);
|
||||
|
||||
auto& info = update_queue[update_count];
|
||||
info.buffer_info = vk::DescriptorBufferInfo{buffer, offset, size};
|
||||
info.buffer_view = view;
|
||||
buffer_infos[buffer_count] = vk::DescriptorBufferInfo{buffer, offset, size};
|
||||
|
||||
writes[update_count++] = vk::WriteDescriptorSet{
|
||||
set, binding, 0, 1,
|
||||
buffer_type, nullptr,
|
||||
&info.buffer_info, &info.buffer_view
|
||||
};
|
||||
writes[write_count++] = vk::WriteDescriptorSet{set, binding, 0, 1, buffer_type, nullptr,
|
||||
&buffer_infos[buffer_count++],
|
||||
view ? &view : nullptr};
|
||||
}
|
||||
|
||||
VulkanState::VulkanState(const std::shared_ptr<VKSwapChain>& swapchain) : swapchain(swapchain) {
|
||||
@ -169,15 +182,19 @@ void VulkanState::SetTexelBuffer(u32 binding, u32 offset, u32 size, const VKBuff
|
||||
descriptors_dirty = true;
|
||||
}
|
||||
|
||||
void VulkanState::SetPresentTexture(const VKTexture& image) {
|
||||
void VulkanState::SetPresentTextures(vk::ImageView view0, vk::ImageView view1, vk::ImageView view2) {
|
||||
auto& set = descriptor_sets[3];
|
||||
updater.PushCombinedImageSamplerUpdate(set, 0, present_sampler, image.GetView());
|
||||
present_view = image.GetView();
|
||||
|
||||
std::array views{view0, view1, view2};
|
||||
updater.PushTextureArrayUpdate(set, 0, present_sampler, views);
|
||||
descriptors_dirty = true;
|
||||
}
|
||||
|
||||
void VulkanState::SetPresentData(DrawInfo data) {
|
||||
present_data = data;
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
|
||||
cmdbuffer.pushConstants(present_pipeline_layout, vk::ShaderStageFlagBits::eFragment |
|
||||
vk::ShaderStageFlagBits::eVertex, 0, sizeof(data), &data);
|
||||
|
||||
}
|
||||
|
||||
void VulkanState::SetPlaceholderColor(u8 red, u8 green, u8 blue, u8 alpha) {
|
||||
@ -480,8 +497,6 @@ void VulkanState::ApplyPresentState() {
|
||||
// Bind present pipeline and descriptors
|
||||
auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer();
|
||||
cmdbuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, present_pipeline.get());
|
||||
cmdbuffer.pushConstants(present_pipeline_layout, vk::ShaderStageFlagBits::eFragment |
|
||||
vk::ShaderStageFlagBits::eVertex, 0, sizeof(present_data), &present_data);
|
||||
|
||||
ApplyCommonState(false);
|
||||
|
||||
@ -561,7 +576,7 @@ void VulkanState::BuildDescriptorLayouts() {
|
||||
{2, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment} // texture_buffer_lut_rgba
|
||||
}};
|
||||
std::array<vk::DescriptorSetLayoutBinding, 1> present_set{{
|
||||
{0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}
|
||||
{0, vk::DescriptorType::eCombinedImageSampler, 3, vk::ShaderStageFlagBits::eFragment}
|
||||
}};
|
||||
|
||||
std::array<vk::DescriptorSetLayoutCreateInfo, DESCRIPTOR_SET_COUNT> create_infos{{
|
||||
|
@ -21,7 +21,7 @@ template <typename T>
|
||||
using OptRef = std::optional<std::reference_wrapper<T>>;
|
||||
|
||||
struct DrawInfo {
|
||||
glm::mat2x3 modelview;
|
||||
glm::mat4 modelview;
|
||||
glm::vec4 i_resolution;
|
||||
glm::vec4 o_resolution;
|
||||
int layer;
|
||||
@ -32,9 +32,11 @@ public:
|
||||
DescriptorUpdater() { Reset(); }
|
||||
~DescriptorUpdater() = default;
|
||||
|
||||
void Reset() { update_count = 0; }
|
||||
void Reset();
|
||||
void Update();
|
||||
|
||||
void PushTextureArrayUpdate(vk::DescriptorSet, u32 biding, vk::Sampler sampler,
|
||||
std::span<vk::ImageView> views);
|
||||
void PushCombinedImageSamplerUpdate(vk::DescriptorSet set, u32 binding,
|
||||
vk::Sampler sampler, vk::ImageView view);
|
||||
void PushBufferUpdate(vk::DescriptorSet set, u32 binding,
|
||||
@ -43,15 +45,16 @@ public:
|
||||
|
||||
private:
|
||||
static constexpr u32 MAX_DESCRIPTORS = 10;
|
||||
static constexpr u32 MAX_UPDATES = 20;
|
||||
struct Descriptor {
|
||||
vk::DescriptorImageInfo image_info;
|
||||
vk::DescriptorBufferInfo buffer_info;
|
||||
vk::BufferView buffer_view;
|
||||
};
|
||||
|
||||
std::array<vk::WriteDescriptorSet, MAX_DESCRIPTORS> writes;
|
||||
std::array<Descriptor, MAX_DESCRIPTORS> update_queue;
|
||||
u32 update_count{};
|
||||
std::array<vk::DescriptorImageInfo, MAX_UPDATES> image_infos;
|
||||
std::array<vk::DescriptorBufferInfo, MAX_UPDATES> buffer_infos;
|
||||
u32 image_count{0}, buffer_count{0}, write_count{0};
|
||||
};
|
||||
|
||||
class VKSwapChain;
|
||||
@ -105,7 +108,7 @@ public:
|
||||
void SetUniformBuffer(u32 binding, u32 offset, u32 size, const VKBuffer& buffer);
|
||||
void SetTexture(u32 binding, const VKTexture& texture);
|
||||
void SetTexelBuffer(u32 binding, u32 offset, u32 size, const VKBuffer& buffer, u32 view_index);
|
||||
void SetPresentTexture(const VKTexture& image);
|
||||
void SetPresentTextures(vk::ImageView view0, vk::ImageView view1, vk::ImageView view2);
|
||||
void SetPresentData(DrawInfo data);
|
||||
void SetPlaceholderColor(u8 red, u8 green, u8 blue, u8 alpha);
|
||||
void UnbindTexture(const VKTexture& image);
|
||||
@ -128,7 +131,6 @@ private:
|
||||
bool rendering{false};
|
||||
vk::ImageView present_view;
|
||||
std::array<vk::ImageView, 4> render_views;
|
||||
DrawInfo present_data;
|
||||
vk::Sampler render_sampler, present_sampler;
|
||||
VKTexture placeholder;
|
||||
|
||||
|
@ -75,6 +75,8 @@ void VKTexture::Create(const Info& create_info) {
|
||||
info.format = vk::Format::eD32SfloatS8Uint;
|
||||
}
|
||||
|
||||
std::cout << "New surface!\n";
|
||||
|
||||
// Create the texture
|
||||
image_size = info.width * info.height * BytesPerPixel(info.format);
|
||||
aspect = GetImageAspect(info.format);
|
||||
@ -136,9 +138,12 @@ void VKTexture::Destroy() {
|
||||
|
||||
auto deleter = [this]() {
|
||||
auto device = g_vk_instace->GetDevice();
|
||||
device.destroyImage(texture);
|
||||
device.destroyImageView(view);
|
||||
device.freeMemory(memory);
|
||||
if (texture) {
|
||||
std::cout << "Surface destroyed!\n";
|
||||
device.destroyImage(texture);
|
||||
device.destroyImageView(view);
|
||||
device.freeMemory(memory);
|
||||
}
|
||||
};
|
||||
|
||||
// Schedule deletion of the texture after it's no longer used
|
||||
@ -270,7 +275,7 @@ void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region,
|
||||
}
|
||||
else if (is_d24s8) {
|
||||
auto data = D24S8ToD32S8(pixels);
|
||||
std::memcpy(buffer, data.data(), data.size());
|
||||
std::memcpy(buffer, data.data(), data.size() * sizeof(data[0]));
|
||||
}
|
||||
else {
|
||||
std::memcpy(buffer, pixels.data(), pixels.size());
|
||||
@ -322,7 +327,7 @@ void VKTexture::Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region
|
||||
}
|
||||
else if (is_d24s8) {
|
||||
auto data = D32S8ToD24S8(memory);
|
||||
std::memcpy(buffer, data.data(), data.size());
|
||||
std::memcpy(buffer, data.data(), data.size() * sizeof(data[0]));
|
||||
}
|
||||
else {
|
||||
std::memcpy(buffer, memory.data(), memory.size());
|
||||
|
Reference in New Issue
Block a user