mirror of
https://github.com/wiiu-env/ftpiiu_plugin.git
synced 2024-11-29 16:14:16 +01:00
Refactor deko3d backend
This commit is contained in:
parent
7591a39cfd
commit
3ab7a31c90
@ -70,6 +70,9 @@ private:
|
|||||||
/// \brief Thread entry point
|
/// \brief Thread entry point
|
||||||
void threadFunc ();
|
void threadFunc ();
|
||||||
|
|
||||||
|
/// \brief Log
|
||||||
|
SharedLog m_log;
|
||||||
|
|
||||||
/// \brief Thread
|
/// \brief Thread
|
||||||
platform::Thread m_thread;
|
platform::Thread m_thread;
|
||||||
|
|
||||||
@ -82,9 +85,6 @@ private:
|
|||||||
/// \brief ImGui window name
|
/// \brief ImGui window name
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
|
||||||
/// \brief Log
|
|
||||||
SharedLog m_log;
|
|
||||||
|
|
||||||
/// \brief Sessions
|
/// \brief Sessions
|
||||||
std::vector<UniqueFtpSession> m_sessions;
|
std::vector<UniqueFtpSession> m_sessions;
|
||||||
|
|
||||||
|
@ -20,15 +20,11 @@
|
|||||||
|
|
||||||
#include "imgui_deko3d.h"
|
#include "imgui_deko3d.h"
|
||||||
|
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
#include "fs.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#include <deko3d.hpp>
|
#include <deko3d.hpp>
|
||||||
#include <switch.h>
|
|
||||||
|
|
||||||
#include <zstd.h>
|
|
||||||
|
|
||||||
#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES
|
#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES
|
||||||
#define GLM_FORCE_INTRINSICS
|
#define GLM_FORCE_INTRINSICS
|
||||||
@ -36,34 +32,24 @@
|
|||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
#include <glm/mat4x4.hpp>
|
#include <glm/mat4x4.hpp>
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
/// \brief deko3d logo width
|
/// \brief Vertex buffer size
|
||||||
constexpr auto LOGO_WIDTH = 500;
|
constexpr auto VTXBUF_SIZE = 1024u * 1024u;
|
||||||
/// \brief deko3d logo height
|
|
||||||
constexpr auto LOGO_HEIGHT = 493;
|
|
||||||
|
|
||||||
/// \brief Number of framebuffers
|
|
||||||
constexpr auto FB_NUM = 2u;
|
|
||||||
|
|
||||||
/// \brief Command buffer size
|
|
||||||
constexpr auto CMDBUF_SIZE = 1024 * 1024;
|
|
||||||
/// \brief Data buffer size
|
|
||||||
constexpr auto DATABUF_SIZE = 1024 * 1024;
|
|
||||||
/// \brief Index buffer size
|
/// \brief Index buffer size
|
||||||
constexpr auto INDEXBUF_SIZE = 1024 * 1024;
|
constexpr auto IDXBUF_SIZE = 1024u * 1024u;
|
||||||
/// \brief Image buffer size
|
|
||||||
constexpr auto IMAGEBUF_SIZE = 16 * 1024 * 1024;
|
|
||||||
|
|
||||||
/// \brief Vertex shader UBO
|
/// \brief Vertex shader UBO
|
||||||
struct VertUBO
|
struct VertUBO
|
||||||
@ -93,27 +79,6 @@ constexpr std::array VERTEX_BUFFER_STATE = {
|
|||||||
DkVtxBufferState{sizeof (ImDrawVert), 0},
|
DkVtxBufferState{sizeof (ImDrawVert), 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief deko3d device
|
|
||||||
dk::UniqueDevice s_device;
|
|
||||||
|
|
||||||
/// \brief Depth buffer memblock
|
|
||||||
dk::UniqueMemBlock s_depthMemBlock;
|
|
||||||
/// \brief Depth buffer image
|
|
||||||
dk::Image s_depthBuffer;
|
|
||||||
|
|
||||||
/// \brief Framebuffer memblock
|
|
||||||
dk::UniqueMemBlock s_fbMemBlock;
|
|
||||||
/// \brief Framebuffer images
|
|
||||||
dk::Image s_frameBuffers[FB_NUM];
|
|
||||||
|
|
||||||
/// \brief Font image
|
|
||||||
dk::Image s_fontTexture;
|
|
||||||
/// \brief deko3d logo image
|
|
||||||
dk::Image s_logoTexture;
|
|
||||||
|
|
||||||
/// \brief deko3d swapchain
|
|
||||||
dk::UniqueSwapchain s_swapchain;
|
|
||||||
|
|
||||||
/// \brief Shader code memblock
|
/// \brief Shader code memblock
|
||||||
dk::UniqueMemBlock s_codeMemBlock;
|
dk::UniqueMemBlock s_codeMemBlock;
|
||||||
/// \brief Shaders (vertex, fragment)
|
/// \brief Shaders (vertex, fragment)
|
||||||
@ -123,116 +88,17 @@ dk::Shader s_shaders[2];
|
|||||||
dk::UniqueMemBlock s_uboMemBlock;
|
dk::UniqueMemBlock s_uboMemBlock;
|
||||||
|
|
||||||
/// \brief Vertex data memblock
|
/// \brief Vertex data memblock
|
||||||
dk::UniqueMemBlock s_vtxMemBlock[FB_NUM];
|
std::vector<dk::UniqueMemBlock> s_vtxMemBlock;
|
||||||
/// \brief Index data memblock
|
/// \brief Index data memblock
|
||||||
dk::UniqueMemBlock s_idxMemBlock[FB_NUM];
|
std::vector<dk::UniqueMemBlock> s_idxMemBlock;
|
||||||
/// \brief Command buffer memblock
|
|
||||||
dk::UniqueMemBlock s_cmdMemBlock[FB_NUM];
|
|
||||||
/// \brief Command buffers
|
|
||||||
dk::UniqueCmdBuf s_cmdBuf[FB_NUM];
|
|
||||||
|
|
||||||
/// \brief Image memblock
|
/// \brief Font image memblock
|
||||||
dk::UniqueMemBlock s_imageMemBlock;
|
dk::UniqueMemBlock s_fontImageMemBlock;
|
||||||
/// \brief Image/Sampler descriptor memblock
|
/// \brief Font texture handle
|
||||||
dk::UniqueMemBlock s_descriptorMemBlock;
|
DkResHandle s_fontTextureHandle;
|
||||||
|
|
||||||
/// \brief deko3d queue
|
|
||||||
dk::UniqueQueue s_queue;
|
|
||||||
|
|
||||||
/// \brief Maximum number of samplers
|
|
||||||
constexpr auto MAX_SAMPLERS = 1;
|
|
||||||
/// \brief Maximum number of images
|
|
||||||
constexpr auto MAX_IMAGES = 2;
|
|
||||||
/// \brief Sample descriptors
|
|
||||||
dk::SamplerDescriptor *s_samplerDescriptors = nullptr;
|
|
||||||
/// \brief Image descriptors
|
|
||||||
dk::ImageDescriptor *s_imageDescriptors = nullptr;
|
|
||||||
|
|
||||||
/// \brief Currently bound image descriptor
|
|
||||||
std::uintptr_t s_boundDescriptor = 0;
|
|
||||||
|
|
||||||
/// \brief Framebuffer width
|
|
||||||
unsigned s_width = 0;
|
|
||||||
/// \brief Framebuffer height
|
|
||||||
unsigned s_height = 0;
|
|
||||||
|
|
||||||
/// \brief Align value
|
|
||||||
/// \tparam T Value type
|
|
||||||
/// \tparam U Alignment type
|
|
||||||
/// \param size_ Value to align
|
|
||||||
/// \param align_ Alignment
|
|
||||||
template <typename T, typename U>
|
|
||||||
constexpr inline std::uint32_t align (T const &size_, U const &align_)
|
|
||||||
{
|
|
||||||
return static_cast<std::uint32_t> (size_ + align_ - 1) & ~(align_ - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Rebuild swapchain
|
|
||||||
/// \param width_ Framebuffer width
|
|
||||||
/// \param height_ Framebuffer height
|
|
||||||
/// \note This assumes the first call is the largest a framebuffer will ever be
|
|
||||||
void rebuildSwapchain (unsigned const width_, unsigned const height_)
|
|
||||||
{
|
|
||||||
// destroy old swapchain
|
|
||||||
s_swapchain = nullptr;
|
|
||||||
|
|
||||||
// create new depth buffer image layout
|
|
||||||
dk::ImageLayout depthLayout;
|
|
||||||
dk::ImageLayoutMaker{s_device}
|
|
||||||
.setFlags (DkImageFlags_UsageRender | DkImageFlags_HwCompression)
|
|
||||||
.setFormat (DkImageFormat_Z24S8)
|
|
||||||
.setDimensions (width_, height_)
|
|
||||||
.initialize (depthLayout);
|
|
||||||
|
|
||||||
auto const depthAlign = depthLayout.getAlignment ();
|
|
||||||
auto const depthSize = depthLayout.getSize ();
|
|
||||||
|
|
||||||
// create depth buffer memblock
|
|
||||||
if (!s_depthMemBlock)
|
|
||||||
{
|
|
||||||
s_depthMemBlock = dk::MemBlockMaker{s_device,
|
|
||||||
align (depthSize, std::max<unsigned> (depthAlign, DK_MEMBLOCK_ALIGNMENT))}
|
|
||||||
.setFlags (DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
|
||||||
.create ();
|
|
||||||
}
|
|
||||||
|
|
||||||
s_depthBuffer.initialize (depthLayout, s_depthMemBlock, 0);
|
|
||||||
|
|
||||||
// create framebuffer image layout
|
|
||||||
dk::ImageLayout fbLayout;
|
|
||||||
dk::ImageLayoutMaker{s_device}
|
|
||||||
.setFlags (
|
|
||||||
DkImageFlags_UsageRender | DkImageFlags_UsagePresent | DkImageFlags_HwCompression)
|
|
||||||
.setFormat (DkImageFormat_RGBA8_Unorm)
|
|
||||||
.setDimensions (width_, height_)
|
|
||||||
.initialize (fbLayout);
|
|
||||||
|
|
||||||
auto const fbAlign = fbLayout.getAlignment ();
|
|
||||||
auto const fbSize = fbLayout.getSize ();
|
|
||||||
|
|
||||||
// create framebuffer memblock
|
|
||||||
if (!s_fbMemBlock)
|
|
||||||
{
|
|
||||||
s_fbMemBlock = dk::MemBlockMaker{s_device,
|
|
||||||
align (FB_NUM * fbSize, std::max<unsigned> (fbAlign, DK_MEMBLOCK_ALIGNMENT))}
|
|
||||||
.setFlags (DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
|
||||||
.create ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize swapchain images
|
|
||||||
std::array<DkImage const *, FB_NUM> swapchainImages;
|
|
||||||
for (unsigned i = 0; i < FB_NUM; ++i)
|
|
||||||
{
|
|
||||||
swapchainImages[i] = &s_frameBuffers[i];
|
|
||||||
s_frameBuffers[i].initialize (fbLayout, s_fbMemBlock, i * fbSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create swapchain
|
|
||||||
s_swapchain = dk::SwapchainMaker{s_device, nwindowGetDefault (), swapchainImages}.create ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Load shader code
|
/// \brief Load shader code
|
||||||
void loadShaders ()
|
void loadShaders (dk::UniqueDevice &device_)
|
||||||
{
|
{
|
||||||
/// \brief Shader file descriptor
|
/// \brief Shader file descriptor
|
||||||
struct ShaderFile
|
struct ShaderFile
|
||||||
@ -250,7 +116,7 @@ void loadShaders ()
|
|||||||
static std::size_t getSize (char const *const path_)
|
static std::size_t getSize (char const *const path_)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
auto const rc = stat (path_, &st);
|
auto const rc = ::stat (path_, &st);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
{
|
{
|
||||||
std::fprintf (stderr, "stat(%s): %s\n", path_, std::strerror (errno));
|
std::fprintf (stderr, "stat(%s): %s\n", path_, std::strerror (errno));
|
||||||
@ -276,13 +142,14 @@ void loadShaders ()
|
|||||||
std::end (shaderFiles),
|
std::end (shaderFiles),
|
||||||
DK_SHADER_CODE_UNUSABLE_SIZE,
|
DK_SHADER_CODE_UNUSABLE_SIZE,
|
||||||
[] (auto const sum_, auto const &file_) {
|
[] (auto const sum_, auto const &file_) {
|
||||||
return sum_ + align (file_.size, DK_SHADER_CODE_ALIGNMENT);
|
return sum_ + imgui::deko3d::align (file_.size, DK_SHADER_CODE_ALIGNMENT);
|
||||||
});
|
});
|
||||||
|
|
||||||
// create shader code memblock
|
// create shader code memblock
|
||||||
s_codeMemBlock = dk::MemBlockMaker{s_device, align (codeSize, DK_MEMBLOCK_ALIGNMENT)}
|
s_codeMemBlock =
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached |
|
dk::MemBlockMaker{device_, imgui::deko3d::align (codeSize, DK_MEMBLOCK_ALIGNMENT)}
|
||||||
DkMemBlockFlags_Code)
|
.setFlags (
|
||||||
|
DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached | DkMemBlockFlags_Code)
|
||||||
.create ();
|
.create ();
|
||||||
|
|
||||||
auto const addr = static_cast<std::uint8_t *> (s_codeMemBlock.getCpuAddr ());
|
auto const addr = static_cast<std::uint8_t *> (s_codeMemBlock.getCpuAddr ());
|
||||||
@ -308,16 +175,16 @@ void loadShaders ()
|
|||||||
|
|
||||||
dk::ShaderMaker{s_codeMemBlock, codeOffset}.initialize (file.shader);
|
dk::ShaderMaker{s_codeMemBlock, codeOffset}.initialize (file.shader);
|
||||||
|
|
||||||
offset = align (offset + file.size, DK_SHADER_CODE_ALIGNMENT);
|
offset = imgui::deko3d::align (offset + file.size, DK_SHADER_CODE_ALIGNMENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Setup render state
|
/// \brief Setup render state
|
||||||
/// \param slot_ Swapchain slot
|
/// \param cmdBuf_ Command buffer
|
||||||
/// \param drawData_ Data to draw
|
/// \param drawData_ Data to draw
|
||||||
/// \param width_ Framebuffer width
|
/// \param width_ Framebuffer width
|
||||||
/// \param height_ Framebuffer height
|
/// \param height_ Framebuffer height
|
||||||
DkCmdList setupRenderState (int const slot_,
|
DkCmdList setupRenderState (dk::UniqueCmdBuf &cmdBuf_,
|
||||||
ImDrawData *const drawData_,
|
ImDrawData *const drawData_,
|
||||||
unsigned const width_,
|
unsigned const width_,
|
||||||
unsigned const height_)
|
unsigned const height_)
|
||||||
@ -335,38 +202,45 @@ DkCmdList setupRenderState (int const slot_,
|
|||||||
vertUBO.projMtx = glm::orthoRH_ZO (L, R, B, T, -1.0f, 1.0f);
|
vertUBO.projMtx = glm::orthoRH_ZO (L, R, B, T, -1.0f, 1.0f);
|
||||||
|
|
||||||
// create command buffer to initialize/reset render state
|
// create command buffer to initialize/reset render state
|
||||||
s_cmdBuf[slot_].setViewports (0, DkViewport{0.0f, 0.0f, width_, height_});
|
cmdBuf_.setViewports (0, DkViewport{0.0f, 0.0f, width_, height_});
|
||||||
s_cmdBuf[slot_].bindShaders (DkStageFlag_GraphicsMask, {&s_shaders[0], &s_shaders[1]});
|
cmdBuf_.bindShaders (DkStageFlag_GraphicsMask, {&s_shaders[0], &s_shaders[1]});
|
||||||
s_cmdBuf[slot_].bindUniformBuffer (DkStage_Vertex,
|
cmdBuf_.bindUniformBuffer (DkStage_Vertex,
|
||||||
0,
|
0,
|
||||||
s_uboMemBlock.getGpuAddr (),
|
s_uboMemBlock.getGpuAddr (),
|
||||||
align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT));
|
imgui::deko3d::align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT));
|
||||||
s_cmdBuf[slot_].pushConstants (s_uboMemBlock.getGpuAddr (),
|
cmdBuf_.pushConstants (s_uboMemBlock.getGpuAddr (),
|
||||||
align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
imgui::deko3d::align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||||
0,
|
0,
|
||||||
sizeof (VertUBO),
|
sizeof (VertUBO),
|
||||||
&vertUBO);
|
&vertUBO);
|
||||||
s_cmdBuf[slot_].bindUniformBuffer (DkStage_Fragment,
|
cmdBuf_.bindUniformBuffer (DkStage_Fragment,
|
||||||
0,
|
0,
|
||||||
s_uboMemBlock.getGpuAddr () + align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
s_uboMemBlock.getGpuAddr () +
|
||||||
align (sizeof (FragUBO), DK_UNIFORM_BUF_ALIGNMENT));
|
imgui::deko3d::align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||||
s_cmdBuf[slot_].bindRasterizerState (dk::RasterizerState{}.setCullMode (DkFace_None));
|
imgui::deko3d::align (sizeof (FragUBO), DK_UNIFORM_BUF_ALIGNMENT));
|
||||||
s_cmdBuf[slot_].bindColorState (dk::ColorState{}.setBlendEnable (0, true));
|
cmdBuf_.bindRasterizerState (dk::RasterizerState{}.setCullMode (DkFace_None));
|
||||||
s_cmdBuf[slot_].bindColorWriteState (dk::ColorWriteState{});
|
cmdBuf_.bindColorState (dk::ColorState{}.setBlendEnable (0, true));
|
||||||
s_cmdBuf[slot_].bindDepthStencilState (dk::DepthStencilState{}.setDepthTestEnable (false));
|
cmdBuf_.bindColorWriteState (dk::ColorWriteState{});
|
||||||
s_cmdBuf[slot_].bindBlendStates (0,
|
cmdBuf_.bindDepthStencilState (dk::DepthStencilState{}.setDepthTestEnable (false));
|
||||||
|
cmdBuf_.bindBlendStates (0,
|
||||||
dk::BlendState{}.setFactors (DkBlendFactor_SrcAlpha,
|
dk::BlendState{}.setFactors (DkBlendFactor_SrcAlpha,
|
||||||
DkBlendFactor_InvSrcAlpha,
|
DkBlendFactor_InvSrcAlpha,
|
||||||
DkBlendFactor_InvSrcAlpha,
|
DkBlendFactor_InvSrcAlpha,
|
||||||
DkBlendFactor_Zero));
|
DkBlendFactor_Zero));
|
||||||
s_cmdBuf[slot_].bindVtxAttribState (VERTEX_ATTRIB_STATE);
|
cmdBuf_.bindVtxAttribState (VERTEX_ATTRIB_STATE);
|
||||||
s_cmdBuf[slot_].bindVtxBufferState (VERTEX_BUFFER_STATE);
|
cmdBuf_.bindVtxBufferState (VERTEX_BUFFER_STATE);
|
||||||
|
|
||||||
return s_cmdBuf[slot_].finishList ();
|
return cmdBuf_.finishList ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void imgui::deko3d::init ()
|
void imgui::deko3d::init (dk::UniqueDevice &device_,
|
||||||
|
dk::UniqueQueue &queue_,
|
||||||
|
dk::UniqueCmdBuf &cmdBuf_,
|
||||||
|
dk::SamplerDescriptor &samplerDescriptor_,
|
||||||
|
dk::ImageDescriptor &imageDescriptor_,
|
||||||
|
DkResHandle fontTextureHandle_,
|
||||||
|
unsigned const imageCount_)
|
||||||
{
|
{
|
||||||
auto &io = ImGui::GetIO ();
|
auto &io = ImGui::GetIO ();
|
||||||
|
|
||||||
@ -374,91 +248,36 @@ void imgui::deko3d::init ()
|
|||||||
io.BackendRendererName = "deko3d";
|
io.BackendRendererName = "deko3d";
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
|
||||||
|
|
||||||
// defer initialization to first newFrame ()
|
|
||||||
}
|
|
||||||
|
|
||||||
void imgui::deko3d::exit ()
|
|
||||||
{
|
|
||||||
// wait for queue to be idle
|
|
||||||
s_queue.waitIdle ();
|
|
||||||
|
|
||||||
// clean up all of the deko3d objects
|
|
||||||
s_queue = nullptr;
|
|
||||||
s_descriptorMemBlock = nullptr;
|
|
||||||
s_imageMemBlock = nullptr;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < FB_NUM; ++i)
|
|
||||||
{
|
|
||||||
s_cmdBuf[i] = nullptr;
|
|
||||||
s_cmdMemBlock[i] = nullptr;
|
|
||||||
s_idxMemBlock[i] = nullptr;
|
|
||||||
s_vtxMemBlock[i] = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_uboMemBlock = nullptr;
|
|
||||||
s_codeMemBlock = nullptr;
|
|
||||||
s_swapchain = nullptr;
|
|
||||||
s_fbMemBlock = nullptr;
|
|
||||||
s_depthMemBlock = nullptr;
|
|
||||||
s_device = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void imgui::deko3d::newFrame ()
|
|
||||||
{
|
|
||||||
if (s_device)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// create deko3d device
|
|
||||||
s_device = dk::DeviceMaker{}.create ();
|
|
||||||
|
|
||||||
// initialize swapchain with maximum resolution
|
|
||||||
rebuildSwapchain (1920, 1080);
|
|
||||||
|
|
||||||
// load shader code
|
// load shader code
|
||||||
loadShaders ();
|
loadShaders (device_);
|
||||||
|
|
||||||
// create UBO memblock
|
// create UBO memblock
|
||||||
s_uboMemBlock = dk::MemBlockMaker{s_device,
|
s_uboMemBlock = dk::MemBlockMaker{device_,
|
||||||
align (align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT) +
|
align (align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT) +
|
||||||
align (sizeof (FragUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
align (sizeof (FragUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||||
DK_MEMBLOCK_ALIGNMENT)}
|
DK_MEMBLOCK_ALIGNMENT)}
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||||
.create ();
|
.create ();
|
||||||
|
|
||||||
// create memblocks for each framebuffer slot
|
// create memblocks for each image slot
|
||||||
for (std::size_t i = 0; i < FB_NUM; ++i)
|
for (std::size_t i = 0; i < imageCount_; ++i)
|
||||||
{
|
{
|
||||||
// create vertex data memblock
|
// create vertex data memblock
|
||||||
s_vtxMemBlock[i] = dk::MemBlockMaker{s_device, align (DATABUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
s_vtxMemBlock.emplace_back (
|
||||||
|
dk::MemBlockMaker{device_, align (VTXBUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||||
.create ();
|
.create ());
|
||||||
|
|
||||||
// create index data memblock
|
// create index data memblock
|
||||||
s_idxMemBlock[i] = dk::MemBlockMaker{s_device, align (INDEXBUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
s_idxMemBlock.emplace_back (
|
||||||
|
dk::MemBlockMaker{device_, align (IDXBUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||||
.create ();
|
.create ());
|
||||||
|
|
||||||
// create command buffer memblock
|
|
||||||
s_cmdMemBlock[i] = dk::MemBlockMaker{s_device, align (CMDBUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
|
||||||
.create ();
|
|
||||||
|
|
||||||
// create command buffer
|
|
||||||
s_cmdBuf[i] = dk::CmdBufMaker{s_device}.create ();
|
|
||||||
s_cmdBuf[i].addMemory (s_cmdMemBlock[i], 0, s_cmdMemBlock[i].getSize ());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create queue
|
|
||||||
s_queue = dk::QueueMaker{s_device}.setFlags (DkQueueFlags_Graphics).create ();
|
|
||||||
|
|
||||||
// create image memblock
|
|
||||||
s_imageMemBlock = dk::MemBlockMaker{s_device, align (IMAGEBUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
|
||||||
.setFlags (DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
|
||||||
.create ();
|
|
||||||
|
|
||||||
// get texture atlas
|
// get texture atlas
|
||||||
auto &io = ImGui::GetIO ();
|
io.Fonts->SetTexID (makeTextureID (fontTextureHandle_));
|
||||||
io.Fonts->SetTexID (nullptr);
|
s_fontTextureHandle = fontTextureHandle_;
|
||||||
unsigned char *pixels;
|
unsigned char *pixels;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
@ -466,139 +285,65 @@ void imgui::deko3d::newFrame ()
|
|||||||
|
|
||||||
// create memblock for transfer
|
// create memblock for transfer
|
||||||
dk::UniqueMemBlock memBlock =
|
dk::UniqueMemBlock memBlock =
|
||||||
dk::MemBlockMaker{s_device, align (width * height, DK_MEMBLOCK_ALIGNMENT)}
|
dk::MemBlockMaker{device_, align (width * height, DK_MEMBLOCK_ALIGNMENT)}
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||||
.create ();
|
.create ();
|
||||||
std::memcpy (memBlock.getCpuAddr (), pixels, width * height);
|
std::memcpy (memBlock.getCpuAddr (), pixels, width * height);
|
||||||
|
|
||||||
// create image/sampler memblock
|
|
||||||
static_assert (sizeof (dk::ImageDescriptor) == DK_IMAGE_DESCRIPTOR_ALIGNMENT);
|
|
||||||
static_assert (sizeof (dk::SamplerDescriptor) == DK_SAMPLER_DESCRIPTOR_ALIGNMENT);
|
|
||||||
static_assert (DK_IMAGE_DESCRIPTOR_ALIGNMENT == DK_SAMPLER_DESCRIPTOR_ALIGNMENT);
|
|
||||||
s_descriptorMemBlock = dk::MemBlockMaker{s_device,
|
|
||||||
align ((MAX_SAMPLERS + MAX_IMAGES) * sizeof (dk::ImageDescriptor), DK_MEMBLOCK_ALIGNMENT)}
|
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
|
||||||
.create ();
|
|
||||||
|
|
||||||
// get cpu address for descriptors
|
|
||||||
s_samplerDescriptors =
|
|
||||||
static_cast<dk::SamplerDescriptor *> (s_descriptorMemBlock.getCpuAddr ());
|
|
||||||
s_imageDescriptors =
|
|
||||||
reinterpret_cast<dk::ImageDescriptor *> (&s_samplerDescriptors[MAX_SAMPLERS]);
|
|
||||||
|
|
||||||
// initialize sampler descriptor
|
// initialize sampler descriptor
|
||||||
s_samplerDescriptors[0].initialize (
|
samplerDescriptor_.initialize (
|
||||||
dk::Sampler{}
|
dk::Sampler{}
|
||||||
.setFilter (DkFilter_Linear, DkFilter_Linear)
|
.setFilter (DkFilter_Linear, DkFilter_Linear)
|
||||||
.setWrapMode (DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge));
|
.setWrapMode (DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge));
|
||||||
|
|
||||||
// use command buffer 0 for initialization
|
|
||||||
auto &cmdBuf = s_cmdBuf[0];
|
|
||||||
|
|
||||||
// initialize texture atlas image layout
|
// initialize texture atlas image layout
|
||||||
dk::ImageLayout layout;
|
dk::ImageLayout layout;
|
||||||
dk::ImageLayoutMaker{s_device}
|
dk::ImageLayoutMaker{device_}
|
||||||
.setFlags (0)
|
.setFlags (0)
|
||||||
.setFormat (DkImageFormat_R8_Unorm)
|
.setFormat (DkImageFormat_R8_Unorm)
|
||||||
.setDimensions (width, height)
|
.setDimensions (width, height)
|
||||||
.initialize (layout);
|
.initialize (layout);
|
||||||
|
|
||||||
// initialize font texture atlas image descriptor
|
auto const fontAlign = layout.getAlignment ();
|
||||||
s_fontTexture.initialize (layout, s_imageMemBlock, 0);
|
auto const fontSize = layout.getSize ();
|
||||||
s_imageDescriptors[0].initialize (s_fontTexture);
|
|
||||||
|
|
||||||
// copy font texture atlas to image view
|
// create image memblock
|
||||||
dk::ImageView imageView{s_fontTexture};
|
s_fontImageMemBlock = dk::MemBlockMaker{device_,
|
||||||
cmdBuf.copyBufferToImage ({memBlock.getGpuAddr ()}, imageView, {0, 0, 0, width, height, 1});
|
align (fontSize, std::max<unsigned> (fontAlign, DK_MEMBLOCK_ALIGNMENT))}
|
||||||
|
.setFlags (DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
||||||
// bind image/sampler descriptors
|
|
||||||
cmdBuf.bindSamplerDescriptorSet (s_descriptorMemBlock.getGpuAddr (), MAX_SAMPLERS);
|
|
||||||
cmdBuf.bindImageDescriptorSet (
|
|
||||||
s_descriptorMemBlock.getGpuAddr () + MAX_SAMPLERS * sizeof (dk::SamplerDescriptor),
|
|
||||||
MAX_IMAGES);
|
|
||||||
|
|
||||||
// submit commands while we get the next image ready to transfer
|
|
||||||
s_queue.submitCommands (cmdBuf.finishList ());
|
|
||||||
|
|
||||||
{
|
|
||||||
// read the deko3d logo
|
|
||||||
auto const path = "romfs:/deko3d.rgba.zst";
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
if (stat (path, &st) != 0)
|
|
||||||
{
|
|
||||||
std::fprintf (stderr, "stat(%s): %s\n", path, std::strerror (errno));
|
|
||||||
std::abort ();
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::File fp;
|
|
||||||
if (!fp.open (path))
|
|
||||||
{
|
|
||||||
std::fprintf (stderr, "open(%s): %s\n", path, std::strerror (errno));
|
|
||||||
std::abort ();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<char> buffer (st.st_size);
|
|
||||||
if (!fp.readAll (buffer.data (), st.st_size))
|
|
||||||
{
|
|
||||||
std::fprintf (stderr, "read(%s): %s\n", path, std::strerror (errno));
|
|
||||||
std::abort ();
|
|
||||||
}
|
|
||||||
|
|
||||||
fp.close ();
|
|
||||||
|
|
||||||
auto const size = ZSTD_getFrameContentSize (buffer.data (), st.st_size);
|
|
||||||
if (ZSTD_isError (size))
|
|
||||||
{
|
|
||||||
std::fprintf (stderr, "ZSTD_getFrameContentSize: %s\n", ZSTD_getErrorName (size));
|
|
||||||
std::abort ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// create memblock for transfer
|
|
||||||
dk::UniqueMemBlock memBlock =
|
|
||||||
dk::MemBlockMaker{s_device, align (size, DK_MEMBLOCK_ALIGNMENT)}
|
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
|
||||||
.create ();
|
.create ();
|
||||||
|
|
||||||
// decompress into transfer memblock
|
// initialize font texture atlas image descriptor
|
||||||
auto const decoded =
|
dk::Image fontTexture;
|
||||||
ZSTD_decompress (memBlock.getCpuAddr (), size, buffer.data (), st.st_size);
|
fontTexture.initialize (layout, s_fontImageMemBlock, 0);
|
||||||
if (ZSTD_isError (decoded))
|
imageDescriptor_.initialize (fontTexture);
|
||||||
|
|
||||||
|
// copy font texture atlas to image view
|
||||||
|
dk::ImageView imageView{fontTexture};
|
||||||
|
cmdBuf_.copyBufferToImage ({memBlock.getGpuAddr ()}, imageView, {0, 0, 0, width, height, 1});
|
||||||
|
|
||||||
|
// submit commands to transfer font texture
|
||||||
|
queue_.submitCommands (cmdBuf_.finishList ());
|
||||||
|
|
||||||
|
// wait for commands to complete before releasing memblock
|
||||||
|
queue_.waitIdle ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void imgui::deko3d::exit ()
|
||||||
{
|
{
|
||||||
std::fprintf (stderr, "ZSTD_decompress: %s\n", ZSTD_getErrorName (decoded));
|
s_fontImageMemBlock = nullptr;
|
||||||
std::abort ();
|
|
||||||
|
s_idxMemBlock.clear ();
|
||||||
|
s_vtxMemBlock.clear ();
|
||||||
|
|
||||||
|
s_uboMemBlock = nullptr;
|
||||||
|
s_codeMemBlock = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize deko3d logo texture image layout
|
void imgui::deko3d::render (dk::UniqueDevice &device_,
|
||||||
dk::ImageLayout layout;
|
dk::UniqueQueue &queue_,
|
||||||
dk::ImageLayoutMaker{s_device}
|
dk::UniqueCmdBuf &cmdBuf_,
|
||||||
.setFlags (0)
|
unsigned const slot_)
|
||||||
.setFormat (DkImageFormat_RGBA8_Unorm)
|
|
||||||
.setDimensions (LOGO_WIDTH, LOGO_HEIGHT)
|
|
||||||
.initialize (layout);
|
|
||||||
|
|
||||||
// initialize deko3d logo texture image descriptor
|
|
||||||
auto const offset = align (width * height, DK_IMAGE_LINEAR_STRIDE_ALIGNMENT);
|
|
||||||
s_logoTexture.initialize (layout, s_imageMemBlock, offset);
|
|
||||||
s_imageDescriptors[1].initialize (s_logoTexture);
|
|
||||||
|
|
||||||
// copy deko3d logo texture to image view
|
|
||||||
dk::ImageView imageView{s_logoTexture};
|
|
||||||
cmdBuf.copyBufferToImage (
|
|
||||||
{memBlock.getGpuAddr ()}, imageView, {0, 0, 0, LOGO_WIDTH, LOGO_HEIGHT, 1});
|
|
||||||
|
|
||||||
// submit commands to transfer deko3d logo texture
|
|
||||||
s_queue.submitCommands (cmdBuf.finishList ());
|
|
||||||
|
|
||||||
// wait for commands to complete before releasing memblocks
|
|
||||||
s_queue.waitIdle ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset command buffer
|
|
||||||
cmdBuf.clear ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void imgui::deko3d::render ()
|
|
||||||
{
|
{
|
||||||
// get ImGui draw data
|
// get ImGui draw data
|
||||||
auto const drawData = ImGui::GetDrawData ();
|
auto const drawData = ImGui::GetDrawData ();
|
||||||
@ -611,34 +356,12 @@ void imgui::deko3d::render ()
|
|||||||
if (width <= 0 || height <= 0)
|
if (width <= 0 || height <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// check if we need to rebuild the swapchain
|
|
||||||
if (width != s_width || height != s_height)
|
|
||||||
{
|
|
||||||
s_width = width;
|
|
||||||
s_height = height;
|
|
||||||
|
|
||||||
s_queue.waitIdle ();
|
|
||||||
rebuildSwapchain (width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get image from queue
|
|
||||||
auto const slot = s_queue.acquireImage (s_swapchain);
|
|
||||||
s_cmdBuf[slot].clear ();
|
|
||||||
|
|
||||||
// bind frame/depth buffers and clear them
|
|
||||||
dk::ImageView colorTarget{s_frameBuffers[slot]};
|
|
||||||
dk::ImageView depthTarget{s_depthBuffer};
|
|
||||||
s_cmdBuf[slot].bindRenderTargets (&colorTarget, &depthTarget);
|
|
||||||
s_cmdBuf[slot].clearColor (0, DkColorMask_RGBA, 0.125f, 0.294f, 0.478f, 1.0f);
|
|
||||||
s_cmdBuf[slot].clearDepthStencil (true, 1.0f, 0xFF, 0);
|
|
||||||
s_queue.submitCommands (s_cmdBuf[slot].finishList ());
|
|
||||||
|
|
||||||
// setup desired render state
|
// setup desired render state
|
||||||
auto const setupCmd = setupRenderState (slot, drawData, width, height);
|
auto const setupCmd = setupRenderState (cmdBuf_, drawData, width, height);
|
||||||
s_queue.submitCommands (setupCmd);
|
queue_.submitCommands (setupCmd);
|
||||||
|
|
||||||
// start with bogus descriptor binding so it'll be updated before first draw call
|
// currently bound texture
|
||||||
s_boundDescriptor = ~static_cast<std::uintptr_t> (0);
|
std::optional<DkResHandle> boundTextureHandle;
|
||||||
|
|
||||||
// will project scissor/clipping rectangles into framebuffer space
|
// will project scissor/clipping rectangles into framebuffer space
|
||||||
// (0,0) unless using multi-viewports
|
// (0,0) unless using multi-viewports
|
||||||
@ -647,41 +370,45 @@ void imgui::deko3d::render ()
|
|||||||
auto const clipScale = drawData->FramebufferScale;
|
auto const clipScale = drawData->FramebufferScale;
|
||||||
|
|
||||||
// check if we need to grow vertex data memblock
|
// check if we need to grow vertex data memblock
|
||||||
if (s_vtxMemBlock[slot].getSize () < drawData->TotalVtxCount * sizeof (ImDrawVert))
|
if (s_vtxMemBlock[slot_].getSize () < drawData->TotalVtxCount * sizeof (ImDrawVert))
|
||||||
{
|
{
|
||||||
s_vtxMemBlock[slot] =
|
// add 10% to avoid growing many frames in a row
|
||||||
dk::MemBlockMaker{s_device,
|
std::size_t const count = drawData->TotalVtxCount * 1.1f;
|
||||||
align (drawData->TotalVtxCount * sizeof (ImDrawVert), DK_MEMBLOCK_ALIGNMENT)}
|
|
||||||
|
s_vtxMemBlock[slot_] =
|
||||||
|
dk::MemBlockMaker{device_, align (count * sizeof (ImDrawVert), DK_MEMBLOCK_ALIGNMENT)}
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||||
.create ();
|
.create ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we need to grow index data memblock
|
// check if we need to grow index data memblock
|
||||||
if (s_idxMemBlock[slot].getSize () < drawData->TotalIdxCount * sizeof (ImDrawIdx))
|
if (s_idxMemBlock[slot_].getSize () < drawData->TotalIdxCount * sizeof (ImDrawIdx))
|
||||||
{
|
{
|
||||||
s_idxMemBlock[slot] =
|
// add 10% to avoid growing many frames in a row
|
||||||
dk::MemBlockMaker{s_device,
|
std::size_t const count = drawData->TotalIdxCount * 1.1f;
|
||||||
align (drawData->TotalIdxCount * sizeof (ImDrawIdx), DK_MEMBLOCK_ALIGNMENT)}
|
|
||||||
|
s_idxMemBlock[slot_] =
|
||||||
|
dk::MemBlockMaker{device_, align (count * sizeof (ImDrawIdx), DK_MEMBLOCK_ALIGNMENT)}
|
||||||
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||||
.create ();
|
.create ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// get base cpu addresses
|
// get base cpu addresses
|
||||||
auto const cpuVtx = static_cast<std::uint8_t *> (s_vtxMemBlock[slot].getCpuAddr ());
|
auto const cpuVtx = static_cast<std::uint8_t *> (s_vtxMemBlock[slot_].getCpuAddr ());
|
||||||
auto const cpuIdx = static_cast<std::uint8_t *> (s_idxMemBlock[slot].getCpuAddr ());
|
auto const cpuIdx = static_cast<std::uint8_t *> (s_idxMemBlock[slot_].getCpuAddr ());
|
||||||
|
|
||||||
// get base gpu addresses
|
// get base gpu addresses
|
||||||
auto const gpuVtx = s_vtxMemBlock[slot].getGpuAddr ();
|
auto const gpuVtx = s_vtxMemBlock[slot_].getGpuAddr ();
|
||||||
auto const gpuIdx = s_idxMemBlock[slot].getGpuAddr ();
|
auto const gpuIdx = s_idxMemBlock[slot_].getGpuAddr ();
|
||||||
|
|
||||||
// get memblock sizes
|
// get memblock sizes
|
||||||
auto const sizeVtx = s_vtxMemBlock[slot].getSize ();
|
auto const sizeVtx = s_vtxMemBlock[slot_].getSize ();
|
||||||
auto const sizeIdx = s_idxMemBlock[slot].getSize ();
|
auto const sizeIdx = s_idxMemBlock[slot_].getSize ();
|
||||||
|
|
||||||
// bind vertex/index data memblocks
|
// bind vertex/index data memblocks
|
||||||
static_assert (sizeof (ImDrawIdx) == 2);
|
static_assert (sizeof (ImDrawIdx) == sizeof (std::uint16_t));
|
||||||
s_cmdBuf[slot].bindVtxBuffer (0, gpuVtx, sizeVtx);
|
cmdBuf_.bindVtxBuffer (0, gpuVtx, sizeVtx);
|
||||||
s_cmdBuf[slot].bindIdxBuffer (DkIdxFormat_Uint16, gpuIdx);
|
cmdBuf_.bindIdxBuffer (DkIdxFormat_Uint16, gpuIdx);
|
||||||
|
|
||||||
// render command lists
|
// render command lists
|
||||||
std::size_t offsetVtx = 0;
|
std::size_t offsetVtx = 0;
|
||||||
@ -718,13 +445,13 @@ void imgui::deko3d::render ()
|
|||||||
if (cmd.UserCallback)
|
if (cmd.UserCallback)
|
||||||
{
|
{
|
||||||
// submit commands to preserve ordering
|
// submit commands to preserve ordering
|
||||||
s_queue.submitCommands (s_cmdBuf[slot].finishList ());
|
queue_.submitCommands (cmdBuf_.finishList ());
|
||||||
|
|
||||||
// user callback, registered via ImDrawList::AddCallback()
|
// user callback, registered via ImDrawList::AddCallback()
|
||||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to
|
||||||
// request the renderer to reset render state.)
|
// request the renderer to reset render state.)
|
||||||
if (cmd.UserCallback == ImDrawCallback_ResetRenderState)
|
if (cmd.UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
s_queue.submitCommands (setupCmd);
|
queue_.submitCommands (setupCmd);
|
||||||
else
|
else
|
||||||
cmd.UserCallback (&cmdList, &cmd);
|
cmd.UserCallback (&cmdList, &cmd);
|
||||||
}
|
}
|
||||||
@ -737,6 +464,7 @@ void imgui::deko3d::render ()
|
|||||||
clip.z = (cmd.ClipRect.z - clipOff.x) * clipScale.x;
|
clip.z = (cmd.ClipRect.z - clipOff.x) * clipScale.x;
|
||||||
clip.w = (cmd.ClipRect.w - clipOff.y) * clipScale.y;
|
clip.w = (cmd.ClipRect.w - clipOff.y) * clipScale.y;
|
||||||
|
|
||||||
|
// check if clip coordinate are outside of the framebuffer
|
||||||
if (clip.x >= width || clip.y >= height || clip.z < 0.0f || clip.w < 0.0f)
|
if (clip.x >= width || clip.y >= height || clip.z < 0.0f || clip.w < 0.0f)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -751,29 +479,24 @@ void imgui::deko3d::render ()
|
|||||||
clip.z = height;
|
clip.z = height;
|
||||||
|
|
||||||
// apply scissor boundaries
|
// apply scissor boundaries
|
||||||
s_cmdBuf[slot].setScissors (
|
cmdBuf_.setScissors (
|
||||||
0, DkScissor{clip.x, clip.y, clip.z - clip.x, clip.w - clip.y});
|
0, DkScissor{clip.x, clip.y, clip.z - clip.x, clip.w - clip.y});
|
||||||
|
|
||||||
// get image descriptor
|
// get texture handle
|
||||||
auto const descriptor = reinterpret_cast<std::uintptr_t> (cmd.TextureId);
|
auto const textureHandle = reinterpret_cast<std::uintptr_t> (cmd.TextureId);
|
||||||
if (descriptor >= MAX_IMAGES)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// check if we need to bind a new texture
|
// check if we need to bind a new texture
|
||||||
if (descriptor != s_boundDescriptor)
|
if (!boundTextureHandle || textureHandle != *boundTextureHandle)
|
||||||
|
{
|
||||||
|
// check if this is the first draw or changing to or from the font texture
|
||||||
|
if (!boundTextureHandle || textureHandle == s_fontTextureHandle ||
|
||||||
|
*boundTextureHandle == s_fontTextureHandle)
|
||||||
{
|
{
|
||||||
s_boundDescriptor = descriptor;
|
|
||||||
|
|
||||||
// bind the new texture
|
|
||||||
s_cmdBuf[slot].bindTextures (
|
|
||||||
DkStage_Fragment, 0, dkMakeTextureHandle (descriptor, 0));
|
|
||||||
|
|
||||||
// check if this is the font texture atlas image descriptor
|
|
||||||
FragUBO fragUBO;
|
FragUBO fragUBO;
|
||||||
fragUBO.font = (descriptor == 0);
|
fragUBO.font = (textureHandle == s_fontTextureHandle);
|
||||||
|
|
||||||
// update fragment shader UBO
|
// update fragment shader UBO
|
||||||
s_cmdBuf[slot].pushConstants (
|
cmdBuf_.pushConstants (
|
||||||
s_uboMemBlock.getGpuAddr () +
|
s_uboMemBlock.getGpuAddr () +
|
||||||
align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
align (sizeof (VertUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||||
align (sizeof (FragUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
align (sizeof (FragUBO), DK_UNIFORM_BUF_ALIGNMENT),
|
||||||
@ -782,8 +505,14 @@ void imgui::deko3d::render ()
|
|||||||
&fragUBO);
|
&fragUBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boundTextureHandle = textureHandle;
|
||||||
|
|
||||||
|
// bind the new texture
|
||||||
|
cmdBuf_.bindTextures (DkStage_Fragment, 0, textureHandle);
|
||||||
|
}
|
||||||
|
|
||||||
// draw the draw list
|
// draw the draw list
|
||||||
s_cmdBuf[slot].drawIndexed (DkPrimitive_Triangles,
|
cmdBuf_.drawIndexed (DkPrimitive_Triangles,
|
||||||
cmd.ElemCount,
|
cmd.ElemCount,
|
||||||
1,
|
1,
|
||||||
cmd.IdxOffset + offsetIdx / sizeof (ImDrawIdx),
|
cmd.IdxOffset + offsetIdx / sizeof (ImDrawIdx),
|
||||||
@ -796,24 +525,6 @@ void imgui::deko3d::render ()
|
|||||||
offsetIdx += idxSize;
|
offsetIdx += idxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for fragments to be completed before discarding depth/stencil buffer
|
|
||||||
s_cmdBuf[slot].barrier (DkBarrier_Fragments, 0);
|
|
||||||
s_cmdBuf[slot].discardDepthStencil ();
|
|
||||||
|
|
||||||
// submit final commands
|
// submit final commands
|
||||||
s_queue.submitCommands (s_cmdBuf[slot].finishList ());
|
queue_.submitCommands (cmdBuf_.finishList ());
|
||||||
|
|
||||||
// present image
|
|
||||||
s_queue.presentImage (s_swapchain, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
void imgui::deko3d::test ()
|
|
||||||
{
|
|
||||||
auto const x1 = (s_width - LOGO_WIDTH) * 0.5f;
|
|
||||||
auto const x2 = x1 + LOGO_WIDTH;
|
|
||||||
auto const y1 = (s_height - LOGO_HEIGHT) * 0.5f;
|
|
||||||
auto const y2 = y1 + LOGO_HEIGHT;
|
|
||||||
|
|
||||||
ImGui::GetBackgroundDrawList ()->AddImage (
|
|
||||||
reinterpret_cast<ImTextureID> (1), ImVec2 (x1, y1), ImVec2 (x2, y2));
|
|
||||||
}
|
}
|
||||||
|
@ -20,16 +20,57 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <deko3d.hpp>
|
||||||
|
|
||||||
namespace imgui
|
namespace imgui
|
||||||
{
|
{
|
||||||
namespace deko3d
|
namespace deko3d
|
||||||
{
|
{
|
||||||
void init ();
|
/// \brief Initialize deko3d
|
||||||
|
/// \param device_ deko3d device (used to allocate vertex/index and font texture buffers)
|
||||||
|
/// \param queue_ deko3d queue (used to run command lists)
|
||||||
|
/// \param cmdBuf_ Command buffer (used to build command lists)
|
||||||
|
/// \param[out] samplerDescriptor_ Sampler descriptor for font texture
|
||||||
|
/// \param[out] imageDescriptor_ Image descriptor for font texture
|
||||||
|
/// \param fontTextureHandle_ Texture handle that references samplerDescriptor_ and imageDescriptor_
|
||||||
|
/// \param imageCount_ Images in the swapchain
|
||||||
|
void init (dk::UniqueDevice &device_,
|
||||||
|
dk::UniqueQueue &queue_,
|
||||||
|
dk::UniqueCmdBuf &cmdBuf_,
|
||||||
|
dk::SamplerDescriptor &samplerDescriptor_,
|
||||||
|
dk::ImageDescriptor &imageDescriptor_,
|
||||||
|
DkResHandle fontTextureHandle_,
|
||||||
|
unsigned imageCount_);
|
||||||
|
|
||||||
|
/// \brief Deinitialize deko3d
|
||||||
void exit ();
|
void exit ();
|
||||||
|
|
||||||
void newFrame ();
|
/// \brief Render ImGui draw list
|
||||||
void render ();
|
/// \param device_ deko3d device (used to reallocate vertex/index buffers)
|
||||||
|
/// \param queue_ deko3d queue (used to run command lists)
|
||||||
|
/// \param cmdBuf_ Command buffer (used to build command lists)
|
||||||
|
/// \param slot_ Image slot
|
||||||
|
void render (dk::UniqueDevice &device_,
|
||||||
|
dk::UniqueQueue &queue_,
|
||||||
|
dk::UniqueCmdBuf &cmdBuf_,
|
||||||
|
unsigned slot_);
|
||||||
|
|
||||||
void test ();
|
/// \brief Make ImGui texture id from deko3d texture handle
|
||||||
|
/// \param handle_ Texture handle
|
||||||
|
inline void *makeTextureID (DkResHandle handle_)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<void *> (static_cast<std::uintptr_t> (handle_));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Align power-of-two value
|
||||||
|
/// \tparam T Value type
|
||||||
|
/// \tparam U Alignment type
|
||||||
|
/// \param size_ Value to align
|
||||||
|
/// \param align_ Alignment
|
||||||
|
template <typename T, typename U>
|
||||||
|
constexpr inline std::uint32_t align (T const &size_, U const &align_)
|
||||||
|
{
|
||||||
|
return static_cast<std::uint32_t> (size_ + align_ - 1) & ~(align_ - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,12 +41,12 @@ static SocketInitConfig const s_socketInitConfig = {
|
|||||||
|
|
||||||
.sb_efficiency = 8,
|
.sb_efficiency = 8,
|
||||||
|
|
||||||
.num_bsd_sessions = 3,
|
.num_bsd_sessions = 1,
|
||||||
.bsd_service_type = BsdServiceType_User,
|
.bsd_service_type = BsdServiceType_User,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Number of FS sessions
|
/// \brief Number of FS sessions
|
||||||
u32 __nx_fs_num_sessions = 3;
|
u32 __nx_fs_num_sessions = 1;
|
||||||
|
|
||||||
/// \brief Called before main ()
|
/// \brief Called before main ()
|
||||||
void userAppInit ()
|
void userAppInit ()
|
||||||
@ -72,11 +72,11 @@ void userAppExit ()
|
|||||||
if (s_fd >= 0)
|
if (s_fd >= 0)
|
||||||
{
|
{
|
||||||
close (s_fd);
|
close (s_fd);
|
||||||
socketExit ();
|
|
||||||
s_fd = -1;
|
s_fd = -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
socketExit ();
|
||||||
nifmExit ();
|
nifmExit ();
|
||||||
plExit ();
|
plExit ();
|
||||||
romfsExit ();
|
romfsExit ();
|
||||||
|
@ -20,22 +20,332 @@
|
|||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
#include "imgui_deko3d.h"
|
#include "imgui_deko3d.h"
|
||||||
#include "imgui_nx.h"
|
#include "imgui_nx.h"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
|
#include <zstd.h>
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
/// \brief deko3d logo width
|
||||||
|
constexpr auto LOGO_WIDTH = 500;
|
||||||
|
/// \brief deko3d logo height
|
||||||
|
constexpr auto LOGO_HEIGHT = 493;
|
||||||
|
|
||||||
|
/// \brief Maximum number of samplers
|
||||||
|
constexpr auto MAX_SAMPLERS = 2;
|
||||||
|
/// \brief Maximum number of images
|
||||||
|
constexpr auto MAX_IMAGES = 2;
|
||||||
|
|
||||||
|
/// \brief Number of framebuffers
|
||||||
|
constexpr auto FB_NUM = 2u;
|
||||||
|
|
||||||
|
/// \brief Command buffer size
|
||||||
|
constexpr auto CMDBUF_SIZE = 1024 * 1024;
|
||||||
|
|
||||||
|
/// \brief Framebuffer width
|
||||||
|
unsigned s_width = 1920;
|
||||||
|
/// \brief Framebuffer height
|
||||||
|
unsigned s_height = 1080;
|
||||||
|
|
||||||
|
/// \brief deko3d device
|
||||||
|
dk::UniqueDevice s_device;
|
||||||
|
|
||||||
|
/// \brief Depth buffer memblock
|
||||||
|
dk::UniqueMemBlock s_depthMemBlock;
|
||||||
|
/// \brief Depth buffer image
|
||||||
|
dk::Image s_depthBuffer;
|
||||||
|
|
||||||
|
/// \brief Framebuffer memblock
|
||||||
|
dk::UniqueMemBlock s_fbMemBlock;
|
||||||
|
/// \brief Framebuffer images
|
||||||
|
dk::Image s_frameBuffers[FB_NUM];
|
||||||
|
|
||||||
|
/// \brief Command buffer memblock
|
||||||
|
dk::UniqueMemBlock s_cmdMemBlock[FB_NUM];
|
||||||
|
/// \brief Command buffers
|
||||||
|
dk::UniqueCmdBuf s_cmdBuf[FB_NUM];
|
||||||
|
|
||||||
|
/// \brief Image memblock
|
||||||
|
dk::UniqueMemBlock s_imageMemBlock;
|
||||||
|
|
||||||
|
/// \brief Image/Sampler descriptor memblock
|
||||||
|
dk::UniqueMemBlock s_descriptorMemBlock;
|
||||||
|
/// \brief Sample descriptors
|
||||||
|
dk::SamplerDescriptor *s_samplerDescriptors = nullptr;
|
||||||
|
/// \brief Image descriptors
|
||||||
|
dk::ImageDescriptor *s_imageDescriptors = nullptr;
|
||||||
|
|
||||||
|
/// \brief deko3d queue
|
||||||
|
dk::UniqueQueue s_queue;
|
||||||
|
|
||||||
|
/// \brief deko3d swapchain
|
||||||
|
dk::UniqueSwapchain s_swapchain;
|
||||||
|
|
||||||
|
/// \brief Rebuild swapchain
|
||||||
|
/// \param width_ Framebuffer width
|
||||||
|
/// \param height_ Framebuffer height
|
||||||
|
/// \note This assumes the first call is the largest a framebuffer will ever be
|
||||||
|
void rebuildSwapchain (unsigned const width_, unsigned const height_)
|
||||||
|
{
|
||||||
|
// destroy old swapchain
|
||||||
|
s_swapchain = nullptr;
|
||||||
|
|
||||||
|
// create new depth buffer image layout
|
||||||
|
dk::ImageLayout depthLayout;
|
||||||
|
dk::ImageLayoutMaker{s_device}
|
||||||
|
.setFlags (DkImageFlags_UsageRender | DkImageFlags_HwCompression)
|
||||||
|
.setFormat (DkImageFormat_Z24S8)
|
||||||
|
.setDimensions (width_, height_)
|
||||||
|
.initialize (depthLayout);
|
||||||
|
|
||||||
|
auto const depthAlign = depthLayout.getAlignment ();
|
||||||
|
auto const depthSize = depthLayout.getSize ();
|
||||||
|
|
||||||
|
// create depth buffer memblock
|
||||||
|
if (!s_depthMemBlock)
|
||||||
|
{
|
||||||
|
s_depthMemBlock = dk::MemBlockMaker{s_device,
|
||||||
|
imgui::deko3d::align (
|
||||||
|
depthSize, std::max<unsigned> (depthAlign, DK_MEMBLOCK_ALIGNMENT))}
|
||||||
|
.setFlags (DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
||||||
|
.create ();
|
||||||
|
}
|
||||||
|
|
||||||
|
s_depthBuffer.initialize (depthLayout, s_depthMemBlock, 0);
|
||||||
|
|
||||||
|
// create framebuffer image layout
|
||||||
|
dk::ImageLayout fbLayout;
|
||||||
|
dk::ImageLayoutMaker{s_device}
|
||||||
|
.setFlags (
|
||||||
|
DkImageFlags_UsageRender | DkImageFlags_UsagePresent | DkImageFlags_HwCompression)
|
||||||
|
.setFormat (DkImageFormat_RGBA8_Unorm)
|
||||||
|
.setDimensions (width_, height_)
|
||||||
|
.initialize (fbLayout);
|
||||||
|
|
||||||
|
auto const fbAlign = fbLayout.getAlignment ();
|
||||||
|
auto const fbSize = fbLayout.getSize ();
|
||||||
|
|
||||||
|
// create framebuffer memblock
|
||||||
|
if (!s_fbMemBlock)
|
||||||
|
{
|
||||||
|
s_fbMemBlock = dk::MemBlockMaker{s_device,
|
||||||
|
imgui::deko3d::align (
|
||||||
|
FB_NUM * fbSize, std::max<unsigned> (fbAlign, DK_MEMBLOCK_ALIGNMENT))}
|
||||||
|
.setFlags (DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
||||||
|
.create ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize swapchain images
|
||||||
|
std::array<DkImage const *, FB_NUM> swapchainImages;
|
||||||
|
for (unsigned i = 0; i < FB_NUM; ++i)
|
||||||
|
{
|
||||||
|
swapchainImages[i] = &s_frameBuffers[i];
|
||||||
|
s_frameBuffers[i].initialize (fbLayout, s_fbMemBlock, i * fbSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create swapchain
|
||||||
|
s_swapchain = dk::SwapchainMaker{s_device, nwindowGetDefault (), swapchainImages}.create ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void deko3dInit ()
|
||||||
|
{
|
||||||
|
// create deko3d device
|
||||||
|
s_device = dk::DeviceMaker{}.create ();
|
||||||
|
|
||||||
|
// initialize swapchain with maximum resolution
|
||||||
|
rebuildSwapchain (1920, 1080);
|
||||||
|
|
||||||
|
// create memblocks for each image slot
|
||||||
|
for (std::size_t i = 0; i < FB_NUM; ++i)
|
||||||
|
{
|
||||||
|
// create command buffer memblock
|
||||||
|
s_cmdMemBlock[i] =
|
||||||
|
dk::MemBlockMaker{s_device, imgui::deko3d::align (CMDBUF_SIZE, DK_MEMBLOCK_ALIGNMENT)}
|
||||||
|
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||||
|
.create ();
|
||||||
|
|
||||||
|
// create command buffer
|
||||||
|
s_cmdBuf[i] = dk::CmdBufMaker{s_device}.create ();
|
||||||
|
s_cmdBuf[i].addMemory (s_cmdMemBlock[i], 0, s_cmdMemBlock[i].getSize ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// create image/sampler memblock
|
||||||
|
static_assert (sizeof (dk::ImageDescriptor) == DK_IMAGE_DESCRIPTOR_ALIGNMENT);
|
||||||
|
static_assert (sizeof (dk::SamplerDescriptor) == DK_SAMPLER_DESCRIPTOR_ALIGNMENT);
|
||||||
|
static_assert (DK_IMAGE_DESCRIPTOR_ALIGNMENT == DK_SAMPLER_DESCRIPTOR_ALIGNMENT);
|
||||||
|
s_descriptorMemBlock = dk::MemBlockMaker{s_device,
|
||||||
|
imgui::deko3d::align (
|
||||||
|
(MAX_SAMPLERS + MAX_IMAGES) * sizeof (dk::ImageDescriptor), DK_MEMBLOCK_ALIGNMENT)}
|
||||||
|
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||||
|
.create ();
|
||||||
|
|
||||||
|
// get cpu address for descriptors
|
||||||
|
s_samplerDescriptors =
|
||||||
|
static_cast<dk::SamplerDescriptor *> (s_descriptorMemBlock.getCpuAddr ());
|
||||||
|
s_imageDescriptors =
|
||||||
|
reinterpret_cast<dk::ImageDescriptor *> (&s_samplerDescriptors[MAX_SAMPLERS]);
|
||||||
|
|
||||||
|
// create queue
|
||||||
|
s_queue = dk::QueueMaker{s_device}.setFlags (DkQueueFlags_Graphics).create ();
|
||||||
|
|
||||||
|
auto &cmdBuf = s_cmdBuf[0];
|
||||||
|
|
||||||
|
// bind image/sampler descriptors
|
||||||
|
cmdBuf.bindSamplerDescriptorSet (s_descriptorMemBlock.getGpuAddr (), MAX_SAMPLERS);
|
||||||
|
cmdBuf.bindImageDescriptorSet (
|
||||||
|
s_descriptorMemBlock.getGpuAddr () + MAX_SAMPLERS * sizeof (dk::SamplerDescriptor),
|
||||||
|
MAX_IMAGES);
|
||||||
|
s_queue.submitCommands (cmdBuf.finishList ());
|
||||||
|
s_queue.waitIdle ();
|
||||||
|
|
||||||
|
cmdBuf.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadLogo ()
|
||||||
|
{
|
||||||
|
// read the deko3d logo
|
||||||
|
auto const path = "romfs:/deko3d.rgba.zst";
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat (path, &st) != 0)
|
||||||
|
{
|
||||||
|
std::fprintf (stderr, "stat(%s): %s\n", path, std::strerror (errno));
|
||||||
|
std::abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::File fp;
|
||||||
|
if (!fp.open (path))
|
||||||
|
{
|
||||||
|
std::fprintf (stderr, "open(%s): %s\n", path, std::strerror (errno));
|
||||||
|
std::abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> buffer (st.st_size);
|
||||||
|
if (!fp.readAll (buffer.data (), st.st_size))
|
||||||
|
{
|
||||||
|
std::fprintf (stderr, "read(%s): %s\n", path, std::strerror (errno));
|
||||||
|
std::abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
fp.close ();
|
||||||
|
|
||||||
|
auto const size = ZSTD_getFrameContentSize (buffer.data (), st.st_size);
|
||||||
|
if (ZSTD_isError (size))
|
||||||
|
{
|
||||||
|
std::fprintf (stderr, "ZSTD_getFrameContentSize: %s\n", ZSTD_getErrorName (size));
|
||||||
|
std::abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// create memblock for transfer
|
||||||
|
dk::UniqueMemBlock memBlock =
|
||||||
|
dk::MemBlockMaker{s_device, imgui::deko3d::align (size, DK_MEMBLOCK_ALIGNMENT)}
|
||||||
|
.setFlags (DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached)
|
||||||
|
.create ();
|
||||||
|
|
||||||
|
// decompress into transfer memblock
|
||||||
|
auto const decoded = ZSTD_decompress (memBlock.getCpuAddr (), size, buffer.data (), st.st_size);
|
||||||
|
if (ZSTD_isError (decoded))
|
||||||
|
{
|
||||||
|
std::fprintf (stderr, "ZSTD_decompress: %s\n", ZSTD_getErrorName (decoded));
|
||||||
|
std::abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize deko3d logo texture image layout
|
||||||
|
dk::ImageLayout layout;
|
||||||
|
dk::ImageLayoutMaker{s_device}
|
||||||
|
.setFlags (0)
|
||||||
|
.setFormat (DkImageFormat_RGBA8_Unorm)
|
||||||
|
.setDimensions (LOGO_WIDTH, LOGO_HEIGHT)
|
||||||
|
.initialize (layout);
|
||||||
|
|
||||||
|
auto const logoAlign = layout.getAlignment ();
|
||||||
|
auto const logoSize = layout.getSize ();
|
||||||
|
|
||||||
|
// create image memblock
|
||||||
|
s_imageMemBlock = dk::MemBlockMaker{s_device,
|
||||||
|
imgui::deko3d::align (logoSize, std::max<unsigned> (logoAlign, DK_MEMBLOCK_ALIGNMENT))}
|
||||||
|
.setFlags (DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image)
|
||||||
|
.create ();
|
||||||
|
|
||||||
|
// initialize sampler descriptor
|
||||||
|
s_samplerDescriptors[1].initialize (
|
||||||
|
dk::Sampler{}
|
||||||
|
.setFilter (DkFilter_Linear, DkFilter_Linear)
|
||||||
|
.setWrapMode (DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge, DkWrapMode_ClampToEdge));
|
||||||
|
|
||||||
|
// initialize deko3d logo texture image descriptor
|
||||||
|
dk::Image logoTexture;
|
||||||
|
logoTexture.initialize (layout, s_imageMemBlock, 0);
|
||||||
|
s_imageDescriptors[1].initialize (logoTexture);
|
||||||
|
|
||||||
|
auto &cmdBuf = s_cmdBuf[0];
|
||||||
|
|
||||||
|
// copy deko3d logo texture to image view
|
||||||
|
dk::ImageView imageView{logoTexture};
|
||||||
|
cmdBuf.copyBufferToImage (
|
||||||
|
{memBlock.getGpuAddr ()}, imageView, {0, 0, 0, LOGO_WIDTH, LOGO_HEIGHT, 1});
|
||||||
|
|
||||||
|
// submit commands to transfer deko3d logo texture
|
||||||
|
s_queue.submitCommands (cmdBuf.finishList ());
|
||||||
|
|
||||||
|
// wait for commands to complete before releasing memblocks
|
||||||
|
s_queue.waitIdle ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void deko3dExit ()
|
||||||
|
{
|
||||||
|
// clean up all of the deko3d objects
|
||||||
|
s_imageMemBlock = nullptr;
|
||||||
|
s_descriptorMemBlock = nullptr;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < FB_NUM; ++i)
|
||||||
|
{
|
||||||
|
s_cmdBuf[i] = nullptr;
|
||||||
|
s_cmdMemBlock[i] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_queue = nullptr;
|
||||||
|
s_swapchain = nullptr;
|
||||||
|
s_fbMemBlock = nullptr;
|
||||||
|
s_depthMemBlock = nullptr;
|
||||||
|
s_device = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool platform::init ()
|
bool platform::init ()
|
||||||
{
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::setvbuf (stderr, nullptr, _IOLBF, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!imgui::nx::init ())
|
if (!imgui::nx::init ())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
imgui::deko3d::init ();
|
deko3dInit ();
|
||||||
|
loadLogo ();
|
||||||
|
imgui::deko3d::init (s_device,
|
||||||
|
s_queue,
|
||||||
|
s_cmdBuf[0],
|
||||||
|
s_samplerDescriptors[0],
|
||||||
|
s_imageDescriptors[0],
|
||||||
|
dkMakeTextureHandle (0, 0),
|
||||||
|
FB_NUM);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -63,10 +373,22 @@ bool platform::loop ()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
imgui::nx::newFrame ();
|
imgui::nx::newFrame ();
|
||||||
imgui::deko3d::newFrame ();
|
|
||||||
ImGui::NewFrame ();
|
ImGui::NewFrame ();
|
||||||
|
|
||||||
imgui::deko3d::test ();
|
auto const &io = ImGui::GetIO ();
|
||||||
|
|
||||||
|
auto const width = io.DisplaySize.x;
|
||||||
|
auto const height = io.DisplaySize.y;
|
||||||
|
|
||||||
|
auto const x1 = (width - LOGO_WIDTH) * 0.5f;
|
||||||
|
auto const x2 = x1 + LOGO_WIDTH;
|
||||||
|
auto const y1 = (height - LOGO_HEIGHT) * 0.5f;
|
||||||
|
auto const y2 = y1 + LOGO_HEIGHT;
|
||||||
|
|
||||||
|
ImGui::GetBackgroundDrawList ()->AddImage (
|
||||||
|
imgui::deko3d::makeTextureID (dkMakeTextureHandle (1, 1)),
|
||||||
|
ImVec2 (x1, y1),
|
||||||
|
ImVec2 (x2, y2));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -75,13 +397,48 @@ void platform::render ()
|
|||||||
{
|
{
|
||||||
ImGui::Render ();
|
ImGui::Render ();
|
||||||
|
|
||||||
imgui::deko3d::render ();
|
auto &io = ImGui::GetIO ();
|
||||||
|
|
||||||
|
if (s_width != io.DisplaySize.x || s_height != io.DisplaySize.y)
|
||||||
|
{
|
||||||
|
s_width = io.DisplaySize.x;
|
||||||
|
s_height = io.DisplaySize.y;
|
||||||
|
rebuildSwapchain (s_width, s_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get image from queue
|
||||||
|
auto const slot = s_queue.acquireImage (s_swapchain);
|
||||||
|
auto &cmdBuf = s_cmdBuf[slot];
|
||||||
|
|
||||||
|
cmdBuf.clear ();
|
||||||
|
|
||||||
|
// bind frame/depth buffers and clear them
|
||||||
|
dk::ImageView colorTarget{s_frameBuffers[slot]};
|
||||||
|
dk::ImageView depthTarget{s_depthBuffer};
|
||||||
|
cmdBuf.bindRenderTargets (&colorTarget, &depthTarget);
|
||||||
|
cmdBuf.clearColor (0, DkColorMask_RGBA, 0.125f, 0.294f, 0.478f, 1.0f);
|
||||||
|
cmdBuf.clearDepthStencil (true, 1.0f, 0xFF, 0);
|
||||||
|
s_queue.submitCommands (cmdBuf.finishList ());
|
||||||
|
|
||||||
|
imgui::deko3d::render (s_device, s_queue, cmdBuf, slot);
|
||||||
|
|
||||||
|
// wait for fragments to be completed before discarding depth/stencil buffer
|
||||||
|
cmdBuf.barrier (DkBarrier_Fragments, 0);
|
||||||
|
cmdBuf.discardDepthStencil ();
|
||||||
|
|
||||||
|
// present image
|
||||||
|
s_queue.presentImage (s_swapchain, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform::exit ()
|
void platform::exit ()
|
||||||
{
|
{
|
||||||
imgui::nx::exit ();
|
imgui::nx::exit ();
|
||||||
|
|
||||||
|
// wait for queue to be idle
|
||||||
|
s_queue.waitIdle ();
|
||||||
|
|
||||||
imgui::deko3d::exit ();
|
imgui::deko3d::exit ();
|
||||||
|
deko3dExit ();
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user