Improve performance by using deko3d to do the framebuffer conversion on the GPU
This commit is contained in:
parent
244d058f1b
commit
fcbc56acc4
@ -63,7 +63,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
|||||||
ASFLAGS := -g $(ARCH)
|
ASFLAGS := -g $(ARCH)
|
||||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
LIBS := -lminizip `freetype-config --libs` -lconfig -lturbojpeg -lpng
|
LIBS := -ldeko3d -lminizip `freetype-config --libs` -lconfig -lturbojpeg -lpng
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# list of directories containing libraries, this must be the top level containing
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
@ -3,14 +3,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "../common/common.h"
|
#include "../common/common.h"
|
||||||
|
#include "nx_graphics.h"
|
||||||
#include "nx_touch.h"
|
#include "nx_touch.h"
|
||||||
|
|
||||||
// Define the desired framebuffer resolution (here we set it to 720p).
|
// Define the desired framebuffer resolution (here we set it to 720p).
|
||||||
#define FB_WIDTH 1280
|
#define FB_WIDTH 1280
|
||||||
#define FB_HEIGHT 720
|
#define FB_HEIGHT 720
|
||||||
|
|
||||||
Framebuffer g_framebufObj;
|
|
||||||
|
|
||||||
uint8_t* g_framebuf;
|
uint8_t* g_framebuf;
|
||||||
u32 g_framebuf_width;
|
u32 g_framebuf_width;
|
||||||
|
|
||||||
@ -120,8 +119,7 @@ int main(int argc, char **argv)
|
|||||||
if (errormsg[0]) error_screen = 1;
|
if (errormsg[0]) error_screen = 1;
|
||||||
|
|
||||||
if (!error_screen) {
|
if (!error_screen) {
|
||||||
framebufferCreate(&g_framebufObj, nwindowGetDefault(), FB_WIDTH, FB_HEIGHT, PIXEL_FORMAT_RGBA_8888, 2);
|
graphicsInit(FB_WIDTH, FB_HEIGHT);
|
||||||
framebufferMakeLinear(&g_framebufObj);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
consoleInit(NULL);
|
consoleInit(NULL);
|
||||||
@ -138,7 +136,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (!error_screen) {
|
if (!error_screen) {
|
||||||
if (!uiUpdate()) break;
|
if (!uiUpdate()) break;
|
||||||
g_framebuf = framebufferBegin(&g_framebufObj, &g_framebuf_width);
|
g_framebuf = graphicsFrameBegin(&g_framebuf_width);
|
||||||
#ifdef PERF_LOG
|
#ifdef PERF_LOG
|
||||||
start_tick = armGetSystemTick();
|
start_tick = armGetSystemTick();
|
||||||
#endif
|
#endif
|
||||||
@ -150,7 +148,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!error_screen) {
|
if (!error_screen) {
|
||||||
framebufferEnd(&g_framebufObj);
|
graphicsFrameEnd();
|
||||||
|
|
||||||
#ifdef PERF_LOG
|
#ifdef PERF_LOG
|
||||||
g_tickdiff_frame = armGetSystemTick() - start_tick;
|
g_tickdiff_frame = armGetSystemTick() - start_tick;
|
||||||
@ -162,7 +160,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!error_screen) {
|
if (!error_screen) {
|
||||||
framebufferClose(&g_framebufObj);
|
graphicsExit();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
consoleExit(NULL);
|
consoleExit(NULL);
|
||||||
|
141
nx_main/nx_graphics.c
Normal file
141
nx_main/nx_graphics.c
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#include <switch.h>
|
||||||
|
#include <deko3d.h>
|
||||||
|
|
||||||
|
#include "nx_graphics.h"
|
||||||
|
|
||||||
|
#define FB_NUM 2
|
||||||
|
#define CMDMEMSIZE 0x1000
|
||||||
|
|
||||||
|
static u32 s_fbWidth, s_fbHeight;
|
||||||
|
|
||||||
|
static DkDevice s_device;
|
||||||
|
static DkMemBlock s_fbMemBlock, s_workMemBlock, s_cmdMemBlock;
|
||||||
|
static DkSwapchain s_swapchain;
|
||||||
|
static DkCmdBuf s_cmdBuf;
|
||||||
|
static DkCmdList s_cmdLists[FB_NUM];
|
||||||
|
static DkFence s_fence;
|
||||||
|
static DkQueue s_queue;
|
||||||
|
|
||||||
|
void graphicsInit(u32 width, u32 height)
|
||||||
|
{
|
||||||
|
DkImageLayoutMaker imgLayoutMaker;
|
||||||
|
DkMemBlockMaker memBlockMaker;
|
||||||
|
|
||||||
|
// Create the device, which is the root object
|
||||||
|
DkDeviceMaker deviceMaker;
|
||||||
|
dkDeviceMakerDefaults(&deviceMaker);
|
||||||
|
s_device = dkDeviceCreate(&deviceMaker);
|
||||||
|
|
||||||
|
// Calculate layout for the framebuffers
|
||||||
|
DkImageLayout fbLayout;
|
||||||
|
dkImageLayoutMakerDefaults(&imgLayoutMaker, s_device);
|
||||||
|
imgLayoutMaker.flags = DkImageFlags_UsagePresent;
|
||||||
|
imgLayoutMaker.format = DkImageFormat_RGBA8_Unorm;
|
||||||
|
imgLayoutMaker.dimensions[0] = s_fbWidth = width;
|
||||||
|
imgLayoutMaker.dimensions[1] = s_fbHeight = height;
|
||||||
|
dkImageLayoutInitialize(&fbLayout, &imgLayoutMaker);
|
||||||
|
|
||||||
|
// Retrieve necessary size and alignment for the framebuffers
|
||||||
|
uint32_t fbSize = dkImageLayoutGetSize(&fbLayout);
|
||||||
|
uint32_t fbAlign = dkImageLayoutGetAlignment(&fbLayout);
|
||||||
|
fbSize = (fbSize + fbAlign - 1) &~ (fbAlign - 1);
|
||||||
|
|
||||||
|
// Create a memory block that will host the framebuffers
|
||||||
|
dkMemBlockMakerDefaults(&memBlockMaker, s_device, FB_NUM*fbSize);
|
||||||
|
memBlockMaker.flags = DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image;
|
||||||
|
s_fbMemBlock = dkMemBlockCreate(&memBlockMaker);
|
||||||
|
|
||||||
|
// Initialize the framebuffers with the layout and backing memory we've just created
|
||||||
|
DkImage fbImages[FB_NUM];
|
||||||
|
DkImage const* swapchainImages[FB_NUM];
|
||||||
|
for (unsigned i = 0; i < FB_NUM; i ++)
|
||||||
|
{
|
||||||
|
swapchainImages[i] = &fbImages[i];
|
||||||
|
dkImageInitialize(&fbImages[i], &fbLayout, s_fbMemBlock, i*fbSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a swapchain out of the framebuffers we've just initialized
|
||||||
|
DkSwapchainMaker swapchainMaker;
|
||||||
|
dkSwapchainMakerDefaults(&swapchainMaker, s_device, nwindowGetDefault(), swapchainImages, FB_NUM);
|
||||||
|
s_swapchain = dkSwapchainCreate(&swapchainMaker);
|
||||||
|
|
||||||
|
// Create a memory block for the linear framebuffer
|
||||||
|
dkMemBlockMakerDefaults(&memBlockMaker, s_device, width*height*4);
|
||||||
|
memBlockMaker.flags = DkMemBlockFlags_CpuCached | DkMemBlockFlags_GpuUncached;
|
||||||
|
s_workMemBlock = dkMemBlockCreate(&memBlockMaker);
|
||||||
|
|
||||||
|
// Create a memory block for the command lists
|
||||||
|
dkMemBlockMakerDefaults(&memBlockMaker, s_device, CMDMEMSIZE);
|
||||||
|
memBlockMaker.flags = DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached;
|
||||||
|
s_cmdMemBlock = dkMemBlockCreate(&memBlockMaker);
|
||||||
|
|
||||||
|
// Create a command buffer
|
||||||
|
DkCmdBufMaker cmdBufMaker;
|
||||||
|
dkCmdBufMakerDefaults(&cmdBufMaker, s_device);
|
||||||
|
s_cmdBuf = dkCmdBufCreate(&cmdBufMaker);
|
||||||
|
dkCmdBufAddMemory(s_cmdBuf, s_cmdMemBlock, 0, CMDMEMSIZE);
|
||||||
|
|
||||||
|
// Define source for linear framebuffer copies
|
||||||
|
const DkCopyBuf linearSrc = {
|
||||||
|
.addr = dkMemBlockGetGpuAddr(s_workMemBlock),
|
||||||
|
.rowLength = 0,
|
||||||
|
.imageHeight = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define rectangle for the copies
|
||||||
|
const DkImageRect copyRect = {
|
||||||
|
.x = 0, .y = 0, .z = 0,
|
||||||
|
.width = width, .height = height, .depth = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Record command lists for the copies
|
||||||
|
for (unsigned i = 0; i < FB_NUM; i ++) {
|
||||||
|
DkImageView tiledDst;
|
||||||
|
dkImageViewDefaults(&tiledDst, &fbImages[i]);
|
||||||
|
dkCmdBufCopyBufferToImage(s_cmdBuf, &linearSrc, &tiledDst, ©Rect, 0);
|
||||||
|
dkCmdBufSignalFence(s_cmdBuf, &s_fence, false);
|
||||||
|
s_cmdLists[i] = dkCmdBufFinishList(s_cmdBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a queue, to which we will submit our command lists
|
||||||
|
DkQueueMaker queueMaker;
|
||||||
|
dkQueueMakerDefaults(&queueMaker, s_device);
|
||||||
|
queueMaker.flags = 0; // we will only use this queue for transferring
|
||||||
|
s_queue = dkQueueCreate(&queueMaker);
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphicsExit(void)
|
||||||
|
{
|
||||||
|
// Make sure the queue is idle before destroying anything
|
||||||
|
dkQueueWaitIdle(s_queue);
|
||||||
|
|
||||||
|
// Destroy all the resources we've created
|
||||||
|
dkQueueDestroy(s_queue);
|
||||||
|
dkCmdBufDestroy(s_cmdBuf);
|
||||||
|
dkMemBlockDestroy(s_cmdMemBlock);
|
||||||
|
dkMemBlockDestroy(s_workMemBlock);
|
||||||
|
dkSwapchainDestroy(s_swapchain);
|
||||||
|
dkMemBlockDestroy(s_fbMemBlock);
|
||||||
|
dkDeviceDestroy(s_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* graphicsFrameBegin(u32* out_stride)
|
||||||
|
{
|
||||||
|
// Ensure the GPU is not reading from the framebuffer
|
||||||
|
dkFenceWait(&s_fence, -1);
|
||||||
|
|
||||||
|
// Return information
|
||||||
|
if (out_stride) *out_stride = s_fbWidth*4;
|
||||||
|
return dkMemBlockGetCpuAddr(s_workMemBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphicsFrameEnd(void)
|
||||||
|
{
|
||||||
|
// Flush the linear framebuffer
|
||||||
|
dkMemBlockFlushCpuCache(s_workMemBlock, 0, s_fbWidth*s_fbHeight*4);
|
||||||
|
|
||||||
|
// Present a frame
|
||||||
|
int slot = dkQueueAcquireImage(s_queue, s_swapchain);
|
||||||
|
dkQueueSubmitCommands(s_queue, s_cmdLists[slot]);
|
||||||
|
dkQueuePresentImage(s_queue, s_swapchain, slot);
|
||||||
|
}
|
9
nx_main/nx_graphics.h
Normal file
9
nx_main/nx_graphics.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
void graphicsInit(u32 width, u32 height);
|
||||||
|
void graphicsExit(void);
|
||||||
|
|
||||||
|
void* graphicsFrameBegin(u32* out_stride);
|
||||||
|
void graphicsFrameEnd(void);
|
Loading…
Reference in New Issue
Block a user