Revert "hoc-clk: add live vdd2, live boost clock and basic pwm dimming"

This reverts commit 15b7df8ef1.
This commit is contained in:
souldbminersmwc
2025-11-09 16:14:52 -05:00
parent 22ec140738
commit 21a3f953d7
3804 changed files with 435 additions and 570162 deletions

View File

@@ -1,545 +0,0 @@
#include "dk_renderer.hpp"
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <switch.h>
#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES /* Enforces GLSL std140/std430 alignment rules for glm types. */
#define GLM_FORCE_INTRINSICS /* Enables usage of SIMD CPU instructions (requiring the above as well). */
#include <glm/vec2.hpp>
namespace nvg {
namespace {
constexpr std::array VertexBufferState = { DkVtxBufferState{sizeof(NVGvertex), 0}, };
constexpr std::array VertexAttribState = {
DkVtxAttribState{0, 0, offsetof(NVGvertex, x), DkVtxAttribSize_2x32, DkVtxAttribType_Float, 0},
DkVtxAttribState{0, 0, offsetof(NVGvertex, u), DkVtxAttribSize_2x32, DkVtxAttribType_Float, 0},
};
struct View {
glm::vec2 size;
};
void UpdateImage(dk::Image &image, CMemPool &scratchPool, dk::Device device, dk::Queue transferQueue, int type, int x, int y, int w, int h, const u8 *data) {
/* Do not proceed if no data is provided upfront. */
if (data == nullptr) {
return;
}
/* Allocate memory from the pool for the image. */
const size_t imageSize = type == NVG_TEXTURE_RGBA ? w * h * 4 : w * h;
CMemPool::Handle tempimgmem = scratchPool.allocate(imageSize, DK_IMAGE_LINEAR_STRIDE_ALIGNMENT);
memcpy(tempimgmem.getCpuAddr(), data, imageSize);
dk::UniqueCmdBuf tempcmdbuf = dk::CmdBufMaker{device}.create();
CMemPool::Handle tempcmdmem = scratchPool.allocate(DK_MEMBLOCK_ALIGNMENT);
tempcmdbuf.addMemory(tempcmdmem.getMemBlock(), tempcmdmem.getOffset(), tempcmdmem.getSize());
dk::ImageView imageView{image};
tempcmdbuf.copyBufferToImage({ tempimgmem.getGpuAddr() }, imageView, { static_cast<uint32_t>(x), static_cast<uint32_t>(y), 0, static_cast<uint32_t>(w), static_cast<uint32_t>(h), 1 });
transferQueue.submitCommands(tempcmdbuf.finishList());
transferQueue.waitIdle();
/* Destroy temp mem. */
tempcmdmem.destroy();
tempimgmem.destroy();
}
}
Texture::Texture(int id) : m_id(id) { /* ... */ }
Texture::~Texture() {
m_image_mem.destroy();
}
void Texture::Initialize(CMemPool &image_pool, CMemPool &scratch_pool, dk::Device device, dk::Queue queue, int type, int w, int h, int image_flags, const u8 *data) {
m_texture_descriptor = {
.width = w,
.height = h,
.type = type,
.flags = image_flags,
};
/* Create an image layout. */
dk::ImageLayout layout;
auto layout_maker = dk::ImageLayoutMaker{device}.setFlags(0).setDimensions(w, h);
if (type == NVG_TEXTURE_RGBA) {
layout_maker.setFormat(DkImageFormat_RGBA8_Unorm);
} else {
layout_maker.setFormat(DkImageFormat_R8_Unorm);
}
layout_maker.initialize(layout);
/* Initialize image. */
m_image_mem = image_pool.allocate(layout.getSize(), layout.getAlignment());
m_image.initialize(layout, m_image_mem.getMemBlock(), m_image_mem.getOffset());
m_image_descriptor.initialize(m_image);
/* Only update the image if the data isn't null. */
if (data != nullptr) {
UpdateImage(m_image, scratch_pool, device, queue, type, 0, 0, w, h, data);
}
}
int Texture::GetId() {
return m_id;
}
const DKNVGtextureDescriptor &Texture::GetDescriptor() {
return m_texture_descriptor;
}
dk::Image &Texture::GetImage() {
return m_image;
}
dk::ImageDescriptor &Texture::GetImageDescriptor() {
return m_image_descriptor;
}
DkRenderer::DkRenderer(unsigned int view_width, unsigned int view_height, dk::Device device, dk::Queue queue, CMemPool &image_mem_pool, CMemPool &code_mem_pool, CMemPool &data_mem_pool) :
m_view_width(view_width), m_view_height(view_height), m_device(device), m_queue(queue), m_image_mem_pool(image_mem_pool), m_code_mem_pool(code_mem_pool), m_data_mem_pool(data_mem_pool), m_image_descriptor_mappings({0})
{
/* Create a dynamic command buffer and allocate memory for it. */
m_dyn_cmd_buf = dk::CmdBufMaker{m_device}.create();
m_dyn_cmd_mem.allocate(m_data_mem_pool, DynamicCmdSize);
m_image_descriptor_set.allocate(m_data_mem_pool);
m_sampler_descriptor_set.allocate(m_data_mem_pool);
m_view_uniform_buffer = m_data_mem_pool.allocate(sizeof(View), DK_UNIFORM_BUF_ALIGNMENT);
m_frag_uniform_buffer = m_data_mem_pool.allocate(sizeof(FragmentUniformSize), DK_UNIFORM_BUF_ALIGNMENT);
/* Create and bind preset samplers. */
dk::UniqueCmdBuf init_cmd_buf = dk::CmdBufMaker{m_device}.create();
CMemPool::Handle init_cmd_mem = m_data_mem_pool.allocate(DK_MEMBLOCK_ALIGNMENT);
init_cmd_buf.addMemory(init_cmd_mem.getMemBlock(), init_cmd_mem.getOffset(), init_cmd_mem.getSize());
for (u8 i = 0; i < SamplerType_Total; i++) {
const DkFilter filter = (i & SamplerType_Nearest) ? DkFilter_Nearest : DkFilter_Linear;
const DkMipFilter mip_filter = (i & SamplerType_Nearest) ? DkMipFilter_Nearest : DkMipFilter_Linear;
const DkWrapMode u_wrap_mode = (i & SamplerType_RepeatX) ? DkWrapMode_Repeat : DkWrapMode_ClampToEdge;
const DkWrapMode v_wrap_mode = (i & SamplerType_RepeatY) ? DkWrapMode_Repeat : DkWrapMode_ClampToEdge;
auto sampler = dk::Sampler{};
auto sampler_descriptor = dk::SamplerDescriptor{};
sampler.setFilter(filter, filter, (i & SamplerType_MipFilter) ? mip_filter : DkMipFilter_None);
sampler.setWrapMode(u_wrap_mode, v_wrap_mode);
sampler_descriptor.initialize(sampler);
m_sampler_descriptor_set.update(init_cmd_buf, i, sampler_descriptor);
}
/* Flush the descriptor cache. */
init_cmd_buf.barrier(DkBarrier_None, DkInvalidateFlags_Descriptors);
m_sampler_descriptor_set.bindForSamplers(init_cmd_buf);
m_image_descriptor_set.bindForImages(init_cmd_buf);
m_queue.submitCommands(init_cmd_buf.finishList());
m_queue.waitIdle();
init_cmd_mem.destroy();
init_cmd_buf.destroy();
}
DkRenderer::~DkRenderer() {
if (m_vertex_buffer) {
m_vertex_buffer->destroy();
}
m_view_uniform_buffer.destroy();
m_frag_uniform_buffer.destroy();
m_textures.clear();
}
int DkRenderer::AcquireImageDescriptor(std::shared_ptr<Texture> texture, int image) {
int free_image_descriptor = m_last_image_descriptor + 1;
int mapping = 0;
for (int desc = 0; desc <= m_last_image_descriptor; desc++) {
mapping = m_image_descriptor_mappings[desc];
/* We've found the image descriptor requested. */
if (mapping == image) {
return desc;
}
/* Update the free image descriptor. */
if (mapping == 0 && free_image_descriptor == m_last_image_descriptor + 1) {
free_image_descriptor = desc;
}
}
/* No descriptors are free. */
if (free_image_descriptor >= static_cast<int>(MaxImages)) {
return -1;
}
/* Update descriptor sets. */
m_image_descriptor_set.update(m_dyn_cmd_buf, free_image_descriptor, texture->GetImageDescriptor());
/* Flush the descriptor cache. */
m_dyn_cmd_buf.barrier(DkBarrier_None, DkInvalidateFlags_Descriptors);
/* Update the map. */
m_image_descriptor_mappings[free_image_descriptor] = image;
m_last_image_descriptor = free_image_descriptor;
return free_image_descriptor;
}
void DkRenderer::FreeImageDescriptor(int image) {
for (int desc = 0; desc <= m_last_image_descriptor; desc++) {
if (m_image_descriptor_mappings[desc] == image) {
m_image_descriptor_mappings[desc] = 0;
}
}
}
void DkRenderer::UpdateVertexBuffer(const void *data, size_t size) {
/* Destroy the existing vertex buffer if it is too small. */
if (m_vertex_buffer && m_vertex_buffer->getSize() < size) {
m_vertex_buffer->destroy();
m_vertex_buffer.reset();
}
/* Create a new buffer if needed. */
if (!m_vertex_buffer) {
m_vertex_buffer = m_data_mem_pool.allocate(size);
}
/* Copy data to the vertex buffer if it exists. */
if (m_vertex_buffer) {
memcpy(m_vertex_buffer->getCpuAddr(), data, size);
}
}
void DkRenderer::SetUniforms(const DKNVGcontext &ctx, int offset, int image) {
m_dyn_cmd_buf.pushConstants(m_frag_uniform_buffer.getGpuAddr(), m_frag_uniform_buffer.getSize(), 0, ctx.fragSize, ctx.uniforms + offset);
m_dyn_cmd_buf.bindUniformBuffer(DkStage_Fragment, 0, m_frag_uniform_buffer.getGpuAddr(), m_frag_uniform_buffer.getSize());
/* Attempt to find a texture. */
const auto texture = this->FindTexture(image);
if (texture == nullptr) {
return;
}
/* Acquire an image descriptor. */
const int image_desc_id = this->AcquireImageDescriptor(texture, image);
if (image_desc_id == -1) {
return;
}
const int image_flags = texture->GetDescriptor().flags;
uint32_t sampler_id = 0;
if (image_flags & NVG_IMAGE_GENERATE_MIPMAPS) sampler_id |= SamplerType_MipFilter;
if (image_flags & NVG_IMAGE_NEAREST) sampler_id |= SamplerType_Nearest;
if (image_flags & NVG_IMAGE_REPEATX) sampler_id |= SamplerType_RepeatX;
if (image_flags & NVG_IMAGE_REPEATY) sampler_id |= SamplerType_RepeatY;
m_dyn_cmd_buf.bindTextures(DkStage_Fragment, 0, dkMakeTextureHandle(image_desc_id, sampler_id));
}
void DkRenderer::DrawFill(const DKNVGcontext &ctx, const DKNVGcall &call) {
DKNVGpath *paths = &ctx.paths[call.pathOffset];
int npaths = call.pathCount;
/* Set the stencils to be used. */
m_dyn_cmd_buf.setStencil(DkFace_FrontAndBack, 0xFF, 0x0, 0xFF);
/* Set the depth stencil state. */
auto depth_stencil_state = dk::DepthStencilState{}
.setStencilTestEnable(true)
.setStencilFrontCompareOp(DkCompareOp_Always)
.setStencilFrontFailOp(DkStencilOp_Keep)
.setStencilFrontDepthFailOp(DkStencilOp_Keep)
.setStencilFrontPassOp(DkStencilOp_IncrWrap)
.setStencilBackCompareOp(DkCompareOp_Always)
.setStencilBackFailOp(DkStencilOp_Keep)
.setStencilBackDepthFailOp(DkStencilOp_Keep)
.setStencilBackPassOp(DkStencilOp_DecrWrap);
m_dyn_cmd_buf.bindDepthStencilState(depth_stencil_state);
/* Configure for shape drawing. */
m_dyn_cmd_buf.bindColorWriteState(dk::ColorWriteState{}.setMask(0, 0));
this->SetUniforms(ctx, call.uniformOffset, 0);
m_dyn_cmd_buf.bindRasterizerState(dk::RasterizerState{}.setCullMode(DkFace_None));
/* Draw vertices. */
for (int i = 0; i < npaths; i++) {
m_dyn_cmd_buf.draw(DkPrimitive_TriangleFan, paths[i].fillCount, 1, paths[i].fillOffset, 0);
}
m_dyn_cmd_buf.bindColorWriteState(dk::ColorWriteState{});
this->SetUniforms(ctx, call.uniformOffset + ctx.fragSize, call.image);
m_dyn_cmd_buf.bindRasterizerState(dk::RasterizerState{});
if (ctx.flags & NVG_ANTIALIAS) {
/* Configure stencil anti-aliasing. */
depth_stencil_state
.setStencilFrontCompareOp(DkCompareOp_Equal)
.setStencilFrontFailOp(DkStencilOp_Keep)
.setStencilFrontDepthFailOp(DkStencilOp_Keep)
.setStencilFrontPassOp(DkStencilOp_Keep)
.setStencilBackCompareOp(DkCompareOp_Equal)
.setStencilBackFailOp(DkStencilOp_Keep)
.setStencilBackDepthFailOp(DkStencilOp_Keep)
.setStencilBackPassOp(DkStencilOp_Keep);
m_dyn_cmd_buf.bindDepthStencilState(depth_stencil_state);
/* Draw fringes. */
for (int i = 0; i < npaths; i++) {
m_dyn_cmd_buf.draw(DkPrimitive_TriangleStrip, paths[i].strokeCount, 1, paths[i].strokeOffset, 0);
}
}
/* Configure and draw fill. */
depth_stencil_state
.setStencilFrontCompareOp(DkCompareOp_NotEqual)
.setStencilFrontFailOp(DkStencilOp_Zero)
.setStencilFrontDepthFailOp(DkStencilOp_Zero)
.setStencilFrontPassOp(DkStencilOp_Zero)
.setStencilBackCompareOp(DkCompareOp_NotEqual)
.setStencilBackFailOp(DkStencilOp_Zero)
.setStencilBackDepthFailOp(DkStencilOp_Zero)
.setStencilBackPassOp(DkStencilOp_Zero);
m_dyn_cmd_buf.bindDepthStencilState(depth_stencil_state);
m_dyn_cmd_buf.draw(DkPrimitive_TriangleStrip, call.triangleCount, 1, call.triangleOffset, 0);
/* Reset the depth stencil state to default. */
m_dyn_cmd_buf.bindDepthStencilState(dk::DepthStencilState{});
}
void DkRenderer::DrawConvexFill(const DKNVGcontext &ctx, const DKNVGcall &call) {
DKNVGpath *paths = &ctx.paths[call.pathOffset];
int npaths = call.pathCount;
this->SetUniforms(ctx, call.uniformOffset, call.image);
for (int i = 0; i < npaths; i++) {
m_dyn_cmd_buf.draw(DkPrimitive_TriangleFan, paths[i].fillCount, 1, paths[i].fillOffset, 0);
/* Draw fringes. */
if (paths[i].strokeCount > 0) {
m_dyn_cmd_buf.draw(DkPrimitive_TriangleStrip, paths[i].strokeCount, 1, paths[i].strokeOffset, 0);
}
}
}
void DkRenderer::DrawStroke(const DKNVGcontext &ctx, const DKNVGcall &call) {
DKNVGpath* paths = &ctx.paths[call.pathOffset];
int npaths = call.pathCount;
if (ctx.flags & NVG_STENCIL_STROKES) {
/* Set the stencil to be used. */
m_dyn_cmd_buf.setStencil(DkFace_Front, 0xFF, 0x0, 0xFF);
/* Configure for filling the stroke base without overlap. */
auto depth_stencil_state = dk::DepthStencilState{}
.setStencilTestEnable(true)
.setStencilFrontCompareOp(DkCompareOp_Equal)
.setStencilFrontFailOp(DkStencilOp_Keep)
.setStencilFrontDepthFailOp(DkStencilOp_Keep)
.setStencilFrontPassOp(DkStencilOp_Incr);
m_dyn_cmd_buf.bindDepthStencilState(depth_stencil_state);
this->SetUniforms(ctx, call.uniformOffset + ctx.fragSize, call.image);
/* Draw vertices. */
for (int i = 0; i < npaths; i++) {
m_dyn_cmd_buf.draw(DkPrimitive_TriangleStrip, paths[i].strokeCount, 1, paths[i].strokeOffset, 0);
}
/* Configure for drawing anti-aliased pixels. */
depth_stencil_state.setStencilFrontPassOp(DkStencilOp_Keep);
m_dyn_cmd_buf.bindDepthStencilState(depth_stencil_state);
this->SetUniforms(ctx, call.uniformOffset, call.image);
/* Draw vertices. */
for (int i = 0; i < npaths; i++) {
m_dyn_cmd_buf.draw(DkPrimitive_TriangleStrip, paths[i].strokeCount, 1, paths[i].strokeOffset, 0);
}
/* Configure for clearing the stencil buffer. */
depth_stencil_state
.setStencilTestEnable(true)
.setStencilFrontCompareOp(DkCompareOp_Always)
.setStencilFrontFailOp(DkStencilOp_Zero)
.setStencilFrontDepthFailOp(DkStencilOp_Zero)
.setStencilFrontPassOp(DkStencilOp_Zero);
m_dyn_cmd_buf.bindDepthStencilState(depth_stencil_state);
/* Draw vertices. */
for (int i = 0; i < npaths; i++) {
m_dyn_cmd_buf.draw(DkPrimitive_TriangleStrip, paths[i].strokeCount, 1, paths[i].strokeOffset, 0);
}
/* Reset the depth stencil state to default. */
m_dyn_cmd_buf.bindDepthStencilState(dk::DepthStencilState{});
} else {
this->SetUniforms(ctx, call.uniformOffset, call.image);
/* Draw vertices. */
for (int i = 0; i < npaths; i++) {
m_dyn_cmd_buf.draw(DkPrimitive_TriangleStrip, paths[i].strokeCount, 1, paths[i].strokeOffset, 0);
}
}
}
void DkRenderer::DrawTriangles(const DKNVGcontext &ctx, const DKNVGcall &call) {
this->SetUniforms(ctx, call.uniformOffset, call.image);
m_dyn_cmd_buf.draw(DkPrimitive_Triangles, call.triangleCount, 1, call.triangleOffset, 0);
}
int DkRenderer::Create(DKNVGcontext &ctx) {
m_vertex_shader.load(m_code_mem_pool, "romfs:/shaders/fill_vsh.dksh");
/* Load the appropriate fragment shader depending on whether AA is enabled. */
if (ctx.flags & NVG_ANTIALIAS) {
m_fragment_shader.load(m_code_mem_pool, "romfs:/shaders/fill_aa_fsh.dksh");
} else {
m_fragment_shader.load(m_code_mem_pool, "romfs:/shaders/fill_fsh.dksh");
}
/* Set the size of fragment uniforms. */
ctx.fragSize = FragmentUniformSize;
return 1;
}
std::shared_ptr<Texture> DkRenderer::FindTexture(int id) {
for (auto it = m_textures.begin(); it != m_textures.end(); it++) {
if ((*it)->GetId() == id) {
return *it;
}
}
return nullptr;
}
int DkRenderer::CreateTexture(const DKNVGcontext &ctx, int type, int w, int h, int image_flags, const unsigned char* data) {
const auto texture_id = m_next_texture_id++;
auto texture = std::make_shared<Texture>(texture_id);
texture->Initialize(m_image_mem_pool, m_data_mem_pool, m_device, m_queue, type, w, h, image_flags, data);
m_textures.push_back(texture);
return texture->GetId();
}
int DkRenderer::DeleteTexture(const DKNVGcontext &ctx, int image) {
bool found = false;
for (auto it = m_textures.begin(); it != m_textures.end();) {
/* Remove textures with the given id. */
if ((*it)->GetId() == image) {
it = m_textures.erase(it);
found = true;
} else {
++it;
}
}
/* Free any used image descriptors. */
this->FreeImageDescriptor(image);
return found;
}
int DkRenderer::UpdateTexture(const DKNVGcontext &ctx, int image, int x, int y, int w, int h, const unsigned char *data) {
const std::shared_ptr<Texture> texture = this->FindTexture(image);
/* Could not find a texture. */
if (texture == nullptr) {
return 0;
}
const DKNVGtextureDescriptor &tex_desc = texture->GetDescriptor();
if (tex_desc.type == NVG_TEXTURE_RGBA) {
data += y * tex_desc.width*4;
} else {
data += y * tex_desc.width;
}
x = 0;
w = tex_desc.width;
UpdateImage(texture->GetImage(), m_data_mem_pool, m_device, m_queue, tex_desc.type, x, y, w, h, data);
return 1;
}
int DkRenderer::GetTextureSize(const DKNVGcontext &ctx, int image, int *w, int *h) {
const auto descriptor = this->GetTextureDescriptor(ctx, image);
if (descriptor == nullptr) {
return 0;
}
*w = descriptor->width;
*h = descriptor->height;
return 1;
}
const DKNVGtextureDescriptor *DkRenderer::GetTextureDescriptor(const DKNVGcontext &ctx, int id) {
for (auto it = m_textures.begin(); it != m_textures.end(); it++) {
if ((*it)->GetId() == id) {
return &(*it)->GetDescriptor();
}
}
return nullptr;
}
void DkRenderer::Flush(DKNVGcontext &ctx) {
if (ctx.ncalls > 0) {
/* Prepare dynamic command buffer. */
m_dyn_cmd_mem.begin(m_dyn_cmd_buf);
/* Update buffers with data. */
this->UpdateVertexBuffer(ctx.verts, ctx.nverts * sizeof(NVGvertex));
/* Enable blending. */
m_dyn_cmd_buf.bindColorState(dk::ColorState{}.setBlendEnable(0, true));
/* Setup. */
m_dyn_cmd_buf.bindShaders(DkStageFlag_GraphicsMask, { m_vertex_shader, m_fragment_shader });
m_dyn_cmd_buf.bindVtxAttribState(VertexAttribState);
m_dyn_cmd_buf.bindVtxBufferState(VertexBufferState);
m_dyn_cmd_buf.bindVtxBuffer(0, m_vertex_buffer->getGpuAddr(), m_vertex_buffer->getSize());
/* Push the view size to the uniform buffer and bind it. */
const auto view = View{glm::vec2{m_view_width, m_view_height}};
m_dyn_cmd_buf.pushConstants(m_view_uniform_buffer.getGpuAddr(), m_view_uniform_buffer.getSize(), 0, sizeof(view), &view);
m_dyn_cmd_buf.bindUniformBuffer(DkStage_Vertex, 0, m_view_uniform_buffer.getGpuAddr(), m_view_uniform_buffer.getSize());
/* Iterate over calls. */
for (int i = 0; i < ctx.ncalls; i++) {
const DKNVGcall &call = ctx.calls[i];
/* Perform blending. */
m_dyn_cmd_buf.bindBlendStates(0, { dk::BlendState{}.setFactors(static_cast<DkBlendFactor>(call.blendFunc.srcRGB), static_cast<DkBlendFactor>(call.blendFunc.dstRGB), static_cast<DkBlendFactor>(call.blendFunc.srcAlpha), static_cast<DkBlendFactor>(call.blendFunc.dstRGB)) });
if (call.type == DKNVG_FILL) {
this->DrawFill(ctx, call);
} else if (call.type == DKNVG_CONVEXFILL) {
this->DrawConvexFill(ctx, call);
} else if (call.type == DKNVG_STROKE) {
this->DrawStroke(ctx, call);
} else if (call.type == DKNVG_TRIANGLES) {
this->DrawTriangles(ctx, call);
}
}
m_queue.submitCommands(m_dyn_cmd_mem.end(m_dyn_cmd_buf));
}
/* Reset calls. */
ctx.nverts = 0;
ctx.npaths = 0;
ctx.ncalls = 0;
ctx.nuniforms = 0;
}
}

View File

@@ -1,69 +0,0 @@
/*
** Sample Framework for deko3d Applications
** CApplication.cpp: Wrapper class containing common application boilerplate
*/
#include "CApplication.h"
CApplication::CApplication()
{
appletLockExit();
appletSetFocusHandlingMode(AppletFocusHandlingMode_NoSuspend);
}
CApplication::~CApplication()
{
appletSetFocusHandlingMode(AppletFocusHandlingMode_SuspendHomeSleep);
appletUnlockExit();
}
void CApplication::run()
{
u64 tick_ref = armGetSystemTick();
u64 tick_saved = tick_ref;
bool focused = appletGetFocusState() == AppletFocusState_InFocus;
onOperationMode(appletGetOperationMode());
for (;;)
{
u32 msg = 0;
Result rc = appletGetMessage(&msg);
if (R_SUCCEEDED(rc))
{
bool should_close = !appletProcessMessage(msg);
if (should_close)
return;
switch (msg)
{
case AppletMessage_FocusStateChanged:
{
bool old_focused = focused;
AppletFocusState state = appletGetFocusState();
focused = state == AppletFocusState_InFocus;
onFocusState(state);
if (focused == old_focused)
break;
if (focused)
{
appletSetFocusHandlingMode(AppletFocusHandlingMode_NoSuspend);
tick_ref += armGetSystemTick() - tick_saved;
}
else
{
tick_saved = armGetSystemTick();
appletSetFocusHandlingMode(AppletFocusHandlingMode_SuspendHomeSleepNotify);
}
break;
}
case AppletMessage_OperationModeChanged:
onOperationMode(appletGetOperationMode());
break;
}
}
if (focused && !onFrame(armTicksToNs(armGetSystemTick() - tick_ref)))
break;
}
}

View File

@@ -1,37 +0,0 @@
/*
** Sample Framework for deko3d Applications
** CExternalImage.cpp: Utility class for loading images from the filesystem
*/
#include "CExternalImage.h"
#include "FileLoader.h"
bool CExternalImage::load(CMemPool& imagePool, CMemPool& scratchPool, dk::Device device, dk::Queue transferQueue, const char* path, uint32_t width, uint32_t height, DkImageFormat format, uint32_t flags)
{
CMemPool::Handle tempimgmem = LoadFile(scratchPool, path, DK_IMAGE_LINEAR_STRIDE_ALIGNMENT);
if (!tempimgmem)
return false;
dk::UniqueCmdBuf tempcmdbuf = dk::CmdBufMaker{device}.create();
CMemPool::Handle tempcmdmem = scratchPool.allocate(DK_MEMBLOCK_ALIGNMENT);
tempcmdbuf.addMemory(tempcmdmem.getMemBlock(), tempcmdmem.getOffset(), tempcmdmem.getSize());
dk::ImageLayout layout;
dk::ImageLayoutMaker{device}
.setFlags(flags)
.setFormat(format)
.setDimensions(width, height)
.initialize(layout);
m_mem = imagePool.allocate(layout.getSize(), layout.getAlignment());
m_image.initialize(layout, m_mem.getMemBlock(), m_mem.getOffset());
m_descriptor.initialize(m_image);
dk::ImageView imageView{m_image};
tempcmdbuf.copyBufferToImage({ tempimgmem.getGpuAddr() }, imageView, { 0, 0, 0, width, height, 1 });
transferQueue.submitCommands(tempcmdbuf.finishList());
transferQueue.waitIdle();
tempcmdmem.destroy();
tempimgmem.destroy();
return true;
}

View File

@@ -1,214 +0,0 @@
/*
** Sample Framework for deko3d Applications
** CIntrusiveTree.cpp: Intrusive red-black tree helper class
*/
#include "CIntrusiveTree.h"
// This red-black tree implementation is mostly based on mtheall's work,
// which can be found here:
// https://github.com/smealum/ctrulib/tree/master/libctru/source/util/rbtree
void CIntrusiveTreeBase::rotate(N* node, N::Leaf leaf)
{
N *tmp = node->child(leaf);
N *parent = node->getParent();
node->child(leaf) = tmp->child(!leaf);
if (tmp->child(!leaf))
tmp->child(!leaf)->setParent(node);
tmp->child(!leaf) = node;
tmp->setParent(parent);
if (parent)
{
if (node == parent->child(!leaf))
parent->child(!leaf) = tmp;
else
parent->child(leaf) = tmp;
}
else
m_root = tmp;
node->setParent(tmp);
}
void CIntrusiveTreeBase::recolor(N* parent, N* node)
{
N *sibling;
while ((!node || node->isBlack()) && node != m_root)
{
N::Leaf leaf = node == parent->left() ? N::Right : N::Left;
sibling = parent->child(leaf);
if (sibling->isRed())
{
sibling->setBlack();
parent->setRed();
rotate(parent, leaf);
sibling = parent->child(leaf);
}
N::Color clr[2];
clr[N::Left] = sibling->left() ? sibling->left()->getColor() : N::Black;
clr[N::Right] = sibling->right() ? sibling->right()->getColor() : N::Black;
if (clr[N::Left] == N::Black && clr[N::Right] == N::Black)
{
sibling->setRed();
node = parent;
parent = node->getParent();
}
else
{
if (clr[leaf] == N::Black)
{
sibling->child(!leaf)->setBlack();
sibling->setRed();
rotate(sibling, !leaf);
sibling = parent->child(leaf);
}
sibling->setColor(parent->getColor());
parent->setBlack();
sibling->child(leaf)->setBlack();
rotate(parent, leaf);
node = m_root;
}
}
if (node)
node->setBlack();
}
auto CIntrusiveTreeBase::walk(N* node, N::Leaf leaf) const -> N*
{
if (node->child(leaf))
{
node = node->child(leaf);
while (node->child(!leaf))
node = node->child(!leaf);
}
else
{
N *parent = node->getParent();
while (parent && node == parent->child(leaf))
{
node = parent;
parent = node->getParent();
}
node = parent;
}
return node;
}
void CIntrusiveTreeBase::insert(N* node, N* parent)
{
node->left() = node->right() = nullptr;
node->setParent(parent);
node->setRed();
while ((parent = node->getParent()) && parent->isRed())
{
N *grandparent = parent->getParent();
N::Leaf leaf = parent == grandparent->left() ? N::Right : N::Left;
N *uncle = grandparent->child(leaf);
if (uncle && uncle->isRed())
{
uncle->setBlack();
parent->setBlack();
grandparent->setRed();
node = grandparent;
}
else
{
if (parent->child(leaf) == node)
{
rotate(parent, leaf);
N* tmp = parent;
parent = node;
node = tmp;
}
parent->setBlack();
grandparent->setRed();
rotate(grandparent, !leaf);
}
}
m_root->setBlack();
}
void CIntrusiveTreeBase::remove(N* node)
{
N::Color color;
N *child, *parent;
if (node->left() && node->right())
{
N *old = node;
node = node->right();
while (node->left())
node = node->left();
parent = old->getParent();
if (parent)
{
if (parent->left() == old)
parent->left() = node;
else
parent->right() = node;
}
else
m_root = node;
child = node->right();
parent = node->getParent();
color = node->getColor();
if (parent == old)
parent = node;
else
{
if (child)
child->setParent(parent);
parent->left() = child;
node->right() = old->right();
old->right()->setParent(node);
}
node->setParent(old->getParent());
node->setColor(old->getColor());
node->left() = old->left();
old->left()->setParent(node);
}
else
{
child = node->left() ? node->right() : node->left();
parent = node->getParent();
color = node->getColor();
if (child)
child->setParent(parent);
if (parent)
{
if (parent->left() == node)
parent->left() = child;
else
parent->right() = child;
}
else
m_root = child;
}
if (color == N::Black)
recolor(parent, child);
}

View File

@@ -1,175 +0,0 @@
/*
** Sample Framework for deko3d Applications
** CMemPool.cpp: Pooled dynamic memory allocation manager class
*/
#include "CMemPool.h"
inline auto CMemPool::_newSlice() -> Slice*
{
Slice* ret = m_sliceHeap.pop();
if (!ret) ret = (Slice*)::malloc(sizeof(Slice));
return ret;
}
inline void CMemPool::_deleteSlice(Slice* s)
{
if (!s) return;
m_sliceHeap.add(s);
}
CMemPool::~CMemPool()
{
m_memMap.iterate([](Slice* s) { ::free(s); });
m_sliceHeap.iterate([](Slice* s) { ::free(s); });
m_blocks.iterate([](Block* blk) {
blk->m_obj.destroy();
::free(blk);
});
}
auto CMemPool::allocate(uint32_t size, uint32_t alignment) -> Handle
{
if (!size) return nullptr;
if (alignment & (alignment - 1)) return nullptr;
size = (size + alignment - 1) &~ (alignment - 1);
#ifdef DEBUG_CMEMPOOL
printf("Allocating size=%u alignment=0x%x\n", size, alignment);
{
Slice* temp = /*m_freeList*/m_memMap.first();
while (temp)
{
printf("-- blk %p | 0x%08x-0x%08x | %s used\n", temp->m_block, temp->m_start, temp->m_end, temp->m_pool ? " " : "not");
temp = /*m_freeList*/m_memMap.next(temp);
}
}
#endif
uint32_t start_offset = 0;
uint32_t end_offset = 0;
Slice* slice = m_freeList.find(size, decltype(m_freeList)::LowerBound);
while (slice)
{
#ifdef DEBUG_CMEMPOOL
printf(" * Checking slice 0x%x - 0x%x\n", slice->m_start, slice->m_end);
#endif
start_offset = (slice->m_start + alignment - 1) &~ (alignment - 1);
end_offset = start_offset + size;
if (end_offset <= slice->m_end)
break;
slice = m_freeList.next(slice);
}
if (!slice)
{
Block* blk = (Block*)::malloc(sizeof(Block));
if (!blk)
return nullptr;
uint32_t unusableSize = (m_flags & DkMemBlockFlags_Code) ? DK_SHADER_CODE_UNUSABLE_SIZE : 0;
uint32_t blkSize = m_blockSize - unusableSize;
blkSize = size > blkSize ? size : blkSize;
blkSize = (blkSize + unusableSize + DK_MEMBLOCK_ALIGNMENT - 1) &~ (DK_MEMBLOCK_ALIGNMENT - 1);
#ifdef DEBUG_CMEMPOOL
printf(" ! Allocating block of size 0x%x\n", blkSize);
#endif
blk->m_obj = dk::MemBlockMaker{m_dev, blkSize}.setFlags(m_flags).create();
if (!blk->m_obj)
{
::free(blk);
return nullptr;
}
slice = _newSlice();
if (!slice)
{
blk->m_obj.destroy();
::free(blk);
return nullptr;
}
slice->m_pool = nullptr;
slice->m_block = blk;
slice->m_start = 0;
slice->m_end = blkSize - unusableSize;
m_memMap.add(slice);
blk->m_cpuAddr = blk->m_obj.getCpuAddr();
blk->m_gpuAddr = blk->m_obj.getGpuAddr();
m_blocks.add(blk);
start_offset = 0;
end_offset = size;
}
else
{
#ifdef DEBUG_CMEMPOOL
printf(" * found it\n");
#endif
m_freeList.remove(slice);
}
if (start_offset != slice->m_start)
{
Slice* t = _newSlice();
if (!t) goto _bad;
t->m_pool = nullptr;
t->m_block = slice->m_block;
t->m_start = slice->m_start;
t->m_end = start_offset;
#ifdef DEBUG_CMEMPOOL
printf("-> subdivide left: %08x-%08x\n", t->m_start, t->m_end);
#endif
m_memMap.addBefore(slice, t);
m_freeList.insert(t, true);
slice->m_start = start_offset;
}
if (end_offset != slice->m_end)
{
Slice* t = _newSlice();
if (!t) goto _bad;
t->m_pool = nullptr;
t->m_block = slice->m_block;
t->m_start = end_offset;
t->m_end = slice->m_end;
#ifdef DEBUG_CMEMPOOL
printf("-> subdivide right: %08x-%08x\n", t->m_start, t->m_end);
#endif
m_memMap.addAfter(slice, t);
m_freeList.insert(t, true);
slice->m_end = end_offset;
}
slice->m_pool = this;
return slice;
_bad:
m_freeList.insert(slice, true);
return nullptr;
}
void CMemPool::_destroy(Slice* slice)
{
slice->m_pool = nullptr;
Slice* left = m_memMap.prev(slice);
Slice* right = m_memMap.next(slice);
if (left && left->canCoalesce(*slice))
{
slice->m_start = left->m_start;
m_freeList.remove(left);
m_memMap.remove(left);
_deleteSlice(left);
}
if (right && slice->canCoalesce(*right))
{
slice->m_end = right->m_end;
m_freeList.remove(right);
m_memMap.remove(right);
_deleteSlice(right);
}
m_freeList.insert(slice, true);
}

View File

@@ -1,62 +0,0 @@
/*
** Sample Framework for deko3d Applications
** CShader.cpp: Utility class for loading shaders from the filesystem
*/
#include "CShader.h"
struct DkshHeader
{
uint32_t magic; // DKSH_MAGIC
uint32_t header_sz; // sizeof(DkshHeader)
uint32_t control_sz;
uint32_t code_sz;
uint32_t programs_off;
uint32_t num_programs;
};
bool CShader::load(CMemPool& pool, const char* path)
{
FILE* f;
DkshHeader hdr;
void* ctrlmem;
m_codemem.destroy();
f = fopen(path, "rb");
if (!f) return false;
if (!fread(&hdr, sizeof(hdr), 1, f))
goto _fail0;
ctrlmem = malloc(hdr.control_sz);
if (!ctrlmem)
goto _fail0;
rewind(f);
if (!fread(ctrlmem, hdr.control_sz, 1, f))
goto _fail1;
m_codemem = pool.allocate(hdr.code_sz, DK_SHADER_CODE_ALIGNMENT);
if (!m_codemem)
goto _fail1;
if (!fread(m_codemem.getCpuAddr(), hdr.code_sz, 1, f))
goto _fail2;
dk::ShaderMaker{m_codemem.getMemBlock(), m_codemem.getOffset()}
.setControl(ctrlmem)
.setProgramId(0)
.initialize(m_shader);
free(ctrlmem);
fclose(f);
return true;
_fail2:
m_codemem.destroy();
_fail1:
free(ctrlmem);
_fail0:
fclose(f);
return false;
}

View File

@@ -1,27 +0,0 @@
/*
** Sample Framework for deko3d Applications
** FileLoader.cpp: Helpers for loading data from the filesystem directly into GPU memory
*/
#include "FileLoader.h"
CMemPool::Handle LoadFile(CMemPool& pool, const char* path, uint32_t alignment)
{
FILE *f = fopen(path, "rb");
if (!f) return nullptr;
fseek(f, 0, SEEK_END);
uint32_t fsize = ftell(f);
rewind(f);
CMemPool::Handle mem = pool.allocate(fsize, alignment);
if (!mem)
{
fclose(f);
return nullptr;
}
fread(mem.getCpuAddr(), fsize, 1, f);
fclose(f);
return mem;
}

View File

@@ -1,18 +0,0 @@
Copyright (C) 2020 fincs
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.