mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-07-04 08:32:15 +02:00
Compare commits
8 Commits
3a8cffef57
...
7f4450f930
Author | SHA1 | Date | |
---|---|---|---|
|
7f4450f930 | ||
|
edb4e2ea56 | ||
|
183f3e0d7e | ||
|
7650c5eb96 | ||
|
0ff197b300 | ||
|
d9fff85bc4 | ||
|
c866c15856 | ||
|
e8ac23e2ee |
@ -1,4 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## 1.6.1
|
||||||
|
+ An improved solution to [the problem that would cause consoles which had previously re-built their SYSTEM partition to brick on update-to-17.0.0](https://gist.github.com/SciresM/2ddb708c812ed585c4d99f54e25205ff) was added.
|
||||||
|
+ In particular, booting atmosphère will now automatically detect the problem and unbrick any consoles which have fallen into this state.
|
||||||
|
+ Some improvements were made to `haze`, including:
|
||||||
|
+ Performance was greatly improved:
|
||||||
|
+ Support was added for GetObjectPropList, which decreases the amount of requests made by ~8x.
|
||||||
|
+ Haze now performs rendering on the GPU, freeing up the CPU to respond to requests in a more timely manner.
|
||||||
|
+ An issue was fixed with how `haze` configures `bMaxPacketSize0` which improves support for USB3.
|
||||||
|
+ General system stability improvements to enhance the user's experience.
|
||||||
## 1.6.0
|
## 1.6.0
|
||||||
+ Basic support was added for 17.0.0.
|
+ Basic support was added for 17.0.0.
|
||||||
+ The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes.
|
+ The console should boot and atmosphère should be fully functional. However, not all modules have been fully updated to reflect the latest changes.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||||
branch = master
|
branch = master
|
||||||
commit = 132558c33865f6a21f06caa31bdfc6b1f92bd9b2
|
commit = 965e05b3cc5ea74de7e3071c3554135e828ce42e
|
||||||
parent = d389ef639ed2988325523f1d95f90030a3370541
|
parent = 183f3e0d7e0c620d213be53c66d9156f55389be2
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.1
|
cmdver = 0.4.1
|
||||||
|
@ -850,7 +850,7 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
ON_SCOPE_EXIT { this->InactivateContentMetaDatabase(StorageId::BuiltInSystem); };
|
ON_SCOPE_EXIT { this->InactivateContentMetaDatabase(StorageId::BuiltInSystem); };
|
||||||
|
|
||||||
/* Open the content meta database and storage. */
|
/* Open the content meta db. */
|
||||||
ContentMetaDatabase meta_db;
|
ContentMetaDatabase meta_db;
|
||||||
R_ABORT_UNLESS(ncm::OpenContentMetaDatabase(std::addressof(meta_db), StorageId::BuiltInSystem));
|
R_ABORT_UNLESS(ncm::OpenContentMetaDatabase(std::addressof(meta_db), StorageId::BuiltInSystem));
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
|
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 6
|
#define ATMOSPHERE_RELEASE_VERSION_MINOR 6
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
|
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
|
||||||
|
|
||||||
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
||||||
|
|
||||||
|
@ -42,7 +42,10 @@ BUILD := build
|
|||||||
SOURCES := source
|
SOURCES := source
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := include ../../libraries/libvapours/include
|
INCLUDES := include ../../libraries/libvapours/include
|
||||||
#ROMFS := romfs
|
ROMFS := romfs
|
||||||
|
|
||||||
|
# Output folders for autogenerated files in romfs
|
||||||
|
OUT_SHADERS := shaders
|
||||||
|
|
||||||
APP_TITLE := USB File Transfer
|
APP_TITLE := USB File Transfer
|
||||||
APP_AUTHOR := Atmosphere-NX
|
APP_AUTHOR := Atmosphere-NX
|
||||||
@ -63,7 +66,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++20
|
|||||||
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 := -lnx
|
LIBS := -ldeko3d -lnx -lm
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# list of directories containing libraries, this must be the top level containing
|
# list of directories containing libraries, this must be the top level containing
|
||||||
@ -90,6 +93,7 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
|
|||||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
GLSLFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.glsl)))
|
||||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@ -155,19 +159,61 @@ ifneq ($(APP_TITLEID),)
|
|||||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(ROMFS),)
|
ifneq ($(strip $(ROMFS)),)
|
||||||
|
ROMFS_TARGETS :=
|
||||||
|
ROMFS_FOLDERS :=
|
||||||
|
ifneq ($(strip $(OUT_SHADERS)),)
|
||||||
|
ROMFS_SHADERS := $(ROMFS)/$(OUT_SHADERS)
|
||||||
|
ROMFS_TARGETS += $(patsubst %.glsl, $(ROMFS_SHADERS)/%.dksh, $(GLSLFILES))
|
||||||
|
ROMFS_FOLDERS += $(ROMFS_SHADERS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
export ROMFS_DEPS := $(foreach file,$(ROMFS_TARGETS),$(CURDIR)/$(file))
|
||||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: $(BUILD) clean all
|
.PHONY: $(BUILD) clean all
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
all: $(BUILD)
|
all: $(ROMFS_TARGETS) | $(BUILD)
|
||||||
|
|
||||||
$(BUILD):
|
$(BUILD):
|
||||||
@[ -d $@ ] || mkdir -p $@
|
@[ -d $@ ] || mkdir -p $@
|
||||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
ifneq ($(strip $(ROMFS_TARGETS)),)
|
||||||
|
|
||||||
|
$(ROMFS_TARGETS): | $(ROMFS_FOLDERS)
|
||||||
|
|
||||||
|
$(ROMFS_FOLDERS):
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
$(ROMFS_SHADERS)/%_vsh.dksh: %_vsh.glsl
|
||||||
|
@echo {vert} $(notdir $<)
|
||||||
|
@uam -s vert -o $@ $<
|
||||||
|
|
||||||
|
$(ROMFS_SHADERS)/%_tcsh.dksh: %_tcsh.glsl
|
||||||
|
@echo {tess_ctrl} $(notdir $<)
|
||||||
|
@uam -s tess_ctrl -o $@ $<
|
||||||
|
|
||||||
|
$(ROMFS_SHADERS)/%_tesh.dksh: %_tesh.glsl
|
||||||
|
@echo {tess_eval} $(notdir $<)
|
||||||
|
@uam -s tess_eval -o $@ $<
|
||||||
|
|
||||||
|
$(ROMFS_SHADERS)/%_gsh.dksh: %_gsh.glsl
|
||||||
|
@echo {geom} $(notdir $<)
|
||||||
|
@uam -s geom -o $@ $<
|
||||||
|
|
||||||
|
$(ROMFS_SHADERS)/%_fsh.dksh: %_fsh.glsl
|
||||||
|
@echo {frag} $(notdir $<)
|
||||||
|
@uam -s frag -o $@ $<
|
||||||
|
|
||||||
|
$(ROMFS_SHADERS)/%.dksh: %.glsl
|
||||||
|
@echo {comp} $(notdir $<)
|
||||||
|
@uam -s comp -o $@ $<
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
clean:
|
clean:
|
||||||
@echo clean ...
|
@echo clean ...
|
||||||
@ -192,9 +238,9 @@ ifeq ($(strip $(APP_JSON)),)
|
|||||||
all : $(OUTPUT).nro
|
all : $(OUTPUT).nro
|
||||||
|
|
||||||
ifeq ($(strip $(NO_NACP)),)
|
ifeq ($(strip $(NO_NACP)),)
|
||||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp $(ROMFS_DEPS)
|
||||||
else
|
else
|
||||||
$(OUTPUT).nro : $(OUTPUT).elf
|
$(OUTPUT).nro : $(OUTPUT).elf $(ROMFS_DEPS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -143,7 +143,7 @@ namespace haze {
|
|||||||
|
|
||||||
if (m_is_applet_mode) {
|
if (m_is_applet_mode) {
|
||||||
/* Print "Applet Mode" in red text. */
|
/* Print "Applet Mode" in red text. */
|
||||||
printf("\n" CONSOLE_ESC(38;5;196m) "Applet Mode" CONSOLE_ESC(0m) "\n");
|
printf("\n" CONSOLE_ESC(31;1m) "Applet Mode" CONSOLE_ESC(0m) "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleUpdate(nullptr);
|
consoleUpdate(nullptr);
|
||||||
|
@ -111,6 +111,14 @@ namespace haze {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr void Deallocate(void *p, size_t n) {
|
constexpr void Deallocate(void *p, size_t n) {
|
||||||
|
/* Check for overflow in alignment. */
|
||||||
|
if (!util::CanAddWithoutOverflow(n, alignof(u64) - 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Align the amount to satisfy allocation for u64. */
|
||||||
|
n = util::AlignUp(n, alignof(u64));
|
||||||
|
|
||||||
/* If the pointer was the last allocation, return the memory to the heap. */
|
/* If the pointer was the last allocation, return the memory to the heap. */
|
||||||
if (static_cast<u8 *>(p) + n == this->GetNextAddress()) {
|
if (static_cast<u8 *>(p) + n == this->GetNextAddress()) {
|
||||||
m_next_address = this->GetNextAddress() - n;
|
m_next_address = this->GetNextAddress() - n;
|
||||||
|
@ -83,6 +83,7 @@ namespace haze {
|
|||||||
Result GetObjectPropDesc(PtpDataParser &dp);
|
Result GetObjectPropDesc(PtpDataParser &dp);
|
||||||
Result GetObjectPropValue(PtpDataParser &dp);
|
Result GetObjectPropValue(PtpDataParser &dp);
|
||||||
Result SetObjectPropValue(PtpDataParser &dp);
|
Result SetObjectPropValue(PtpDataParser &dp);
|
||||||
|
Result GetObjectPropList(PtpDataParser &dp);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ namespace haze {
|
|||||||
PtpOperationCode_MtpGetObjectPropDesc,
|
PtpOperationCode_MtpGetObjectPropDesc,
|
||||||
PtpOperationCode_MtpGetObjectPropValue,
|
PtpOperationCode_MtpGetObjectPropValue,
|
||||||
PtpOperationCode_MtpSetObjectPropValue,
|
PtpOperationCode_MtpSetObjectPropValue,
|
||||||
|
PtpOperationCode_MtpGetObjPropList,
|
||||||
PtpOperationCode_AndroidGetPartialObject64,
|
PtpOperationCode_AndroidGetPartialObject64,
|
||||||
PtpOperationCode_AndroidSendPartialObject,
|
PtpOperationCode_AndroidSendPartialObject,
|
||||||
PtpOperationCode_AndroidTruncateObject,
|
PtpOperationCode_AndroidTruncateObject,
|
||||||
|
@ -38,5 +38,7 @@ namespace haze {
|
|||||||
R_DEFINE_ERROR_RESULT(UnknownPropertyCode, 14);
|
R_DEFINE_ERROR_RESULT(UnknownPropertyCode, 14);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidPropertyValue, 15);
|
R_DEFINE_ERROR_RESULT(InvalidPropertyValue, 15);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidArgument, 16);
|
R_DEFINE_ERROR_RESULT(InvalidArgument, 16);
|
||||||
|
R_DEFINE_ERROR_RESULT(GroupSpecified, 17);
|
||||||
|
R_DEFINE_ERROR_RESULT(DepthSpecified, 18);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
15
troposphere/haze/source/console_fsh.glsl
Normal file
15
troposphere/haze/source/console_fsh.glsl
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout (location = 0) noperspective in vec3 inTexCoord;
|
||||||
|
layout (location = 1) flat in vec4 inFrontPal;
|
||||||
|
layout (location = 2) flat in vec4 inBackPal;
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout (binding = 0) uniform sampler2DArray tileset;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float value = texture(tileset, inTexCoord).r;
|
||||||
|
outColor = mix(inBackPal, inFrontPal, value);
|
||||||
|
}
|
35
troposphere/haze/source/console_vsh.glsl
Normal file
35
troposphere/haze/source/console_vsh.glsl
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
layout (location = 0) in float inTileId;
|
||||||
|
layout (location = 1) in uvec2 inColorId;
|
||||||
|
|
||||||
|
layout (location = 0) out vec3 outTexCoord;
|
||||||
|
layout (location = 1) out vec4 outFrontPal;
|
||||||
|
layout (location = 2) out vec4 outBackPal;
|
||||||
|
|
||||||
|
layout (std140, binding = 0) uniform Config
|
||||||
|
{
|
||||||
|
vec4 dimensions;
|
||||||
|
vec4 vertices[3];
|
||||||
|
vec4 palettes[24];
|
||||||
|
} u;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float id = float(gl_InstanceID);
|
||||||
|
float tileRow = floor(id / u.dimensions.z);
|
||||||
|
float tileCol = id - tileRow * u.dimensions.z;
|
||||||
|
|
||||||
|
vec2 basePos;
|
||||||
|
basePos.x = 2.0 * (tileCol + 0.5) / u.dimensions.z - 1.0;
|
||||||
|
basePos.y = 2.0 * (1.0 - (tileRow + 0.5) / u.dimensions.w) - 1.0;
|
||||||
|
|
||||||
|
vec2 vtxData = u.vertices[gl_VertexID].xy;
|
||||||
|
vec2 scale = vec2(1.0) / u.dimensions.zw;
|
||||||
|
gl_Position.xy = vtxData * scale + basePos;
|
||||||
|
gl_Position.zw = vec2(0.5, 1.0);
|
||||||
|
|
||||||
|
outTexCoord = vec3(u.vertices[gl_VertexID].zw, inTileId);
|
||||||
|
outFrontPal = u.palettes[inColorId.x];
|
||||||
|
outBackPal = u.palettes[inColorId.y];
|
||||||
|
}
|
487
troposphere/haze/source/gpu_console.c
Normal file
487
troposphere/haze/source/gpu_console.c
Normal file
@ -0,0 +1,487 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/iosupport.h>
|
||||||
|
|
||||||
|
#include <switch.h>
|
||||||
|
#include <deko3d.h>
|
||||||
|
|
||||||
|
// Define the desired number of framebuffers
|
||||||
|
#define FB_NUM 2
|
||||||
|
|
||||||
|
// Define the size of the memory block that will hold code
|
||||||
|
#define CODEMEMSIZE (64*1024)
|
||||||
|
|
||||||
|
// Define the size of the memory block that will hold command lists
|
||||||
|
#define CMDMEMSIZE (64*1024)
|
||||||
|
|
||||||
|
#define NUM_IMAGE_SLOTS 1
|
||||||
|
#define NUM_SAMPLER_SLOTS 1
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float pos[2];
|
||||||
|
float tex[2];
|
||||||
|
} VertexDef;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float red;
|
||||||
|
float green;
|
||||||
|
float blue;
|
||||||
|
float alpha;
|
||||||
|
} PaletteColor;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float dimensions[4];
|
||||||
|
VertexDef vertices[3];
|
||||||
|
PaletteColor palettes[24];
|
||||||
|
} ConsoleConfig;
|
||||||
|
|
||||||
|
static const VertexDef g_vertexData[3] = {
|
||||||
|
{ { 0.0f, +1.0f }, { 0.5f, 0.0f, } },
|
||||||
|
{ { -1.0f, -1.0f }, { 0.0f, 1.0f, } },
|
||||||
|
{ { +1.0f, -1.0f }, { 1.0f, 1.0f, } },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const PaletteColor g_paletteData[24] = {
|
||||||
|
{ 0.0f, 0.0f, 0.0f, 0.0f }, // black
|
||||||
|
{ 0.5f, 0.0f, 0.0f, 1.0f }, // red
|
||||||
|
{ 0.0f, 0.5f, 0.0f, 1.0f }, // green
|
||||||
|
{ 0.5f, 0.5f, 0.0f, 1.0f }, // yellow
|
||||||
|
{ 0.0f, 0.0f, 0.5f, 1.0f }, // blue
|
||||||
|
{ 0.5f, 0.0f, 0.5f, 1.0f }, // magenta
|
||||||
|
{ 0.0f, 0.5f, 0.5f, 1.0f }, // cyan
|
||||||
|
{ 0.75f, 0.75f, 0.75f, 1.0f }, // white
|
||||||
|
|
||||||
|
{ 0.5f, 0.5f, 0.5f, 1.0f }, // bright black
|
||||||
|
{ 1.0f, 0.0f, 0.0f, 1.0f }, // bright red
|
||||||
|
{ 0.0f, 1.0f, 0.0f, 1.0f }, // bright green
|
||||||
|
{ 1.0f, 1.0f, 0.0f, 1.0f }, // bright yellow
|
||||||
|
{ 0.0f, 0.0f, 1.0f, 1.0f }, // bright blue
|
||||||
|
{ 1.0f, 0.0f, 1.0f, 1.0f }, // bright magenta
|
||||||
|
{ 0.0f, 1.0f, 1.0f, 1.0f }, // bright cyan
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f }, // bright white
|
||||||
|
|
||||||
|
{ 0.0f, 0.0f, 0.0f, 0.0f }, // faint black
|
||||||
|
{ 0.25f, 0.0f, 0.0f, 1.0f }, // faint red
|
||||||
|
{ 0.0f, 0.25f, 0.0f, 1.0f }, // faint green
|
||||||
|
{ 0.25f, 0.25f, 0.0f, 1.0f }, // faint yellow
|
||||||
|
{ 0.0f, 0.0f, 0.25f, 1.0f }, // faint blue
|
||||||
|
{ 0.25f, 0.0f, 0.25f, 1.0f }, // faint magenta
|
||||||
|
{ 0.0f, 0.25f, 0.25f, 1.0f }, // faint cyan
|
||||||
|
{ 0.375f, 0.375f, 0.375f, 1.0f }, // faint white
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t tileId;
|
||||||
|
uint8_t frontPal;
|
||||||
|
uint8_t backPal;
|
||||||
|
} ConsoleChar;
|
||||||
|
|
||||||
|
static const DkVtxAttribState g_attribState[] = {
|
||||||
|
{ .bufferId=0, .isFixed=0, .offset=offsetof(ConsoleChar,tileId), .size=DkVtxAttribSize_1x16, .type=DkVtxAttribType_Uscaled, .isBgra=0 },
|
||||||
|
{ .bufferId=0, .isFixed=0, .offset=offsetof(ConsoleChar,frontPal), .size=DkVtxAttribSize_2x8, .type=DkVtxAttribType_Uint, .isBgra=0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const DkVtxBufferState g_vtxbufState[] = {
|
||||||
|
{ .stride=sizeof(ConsoleChar), .divisor=1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GpuRenderer {
|
||||||
|
ConsoleRenderer base;
|
||||||
|
|
||||||
|
bool initialized;
|
||||||
|
|
||||||
|
DkDevice device;
|
||||||
|
DkQueue queue;
|
||||||
|
|
||||||
|
DkMemBlock imageMemBlock;
|
||||||
|
DkMemBlock codeMemBlock;
|
||||||
|
DkMemBlock dataMemBlock;
|
||||||
|
|
||||||
|
DkSwapchain swapchain;
|
||||||
|
DkImage framebuffers[FB_NUM];
|
||||||
|
DkImage tileset;
|
||||||
|
ConsoleChar* charBuf;
|
||||||
|
|
||||||
|
uint32_t codeMemOffset;
|
||||||
|
DkShader vertexShader;
|
||||||
|
DkShader fragmentShader;
|
||||||
|
|
||||||
|
DkCmdBuf cmdbuf;
|
||||||
|
DkCmdList cmdsBindFramebuffer[FB_NUM];
|
||||||
|
DkCmdList cmdsRender;
|
||||||
|
|
||||||
|
DkFence lastRenderFence;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct GpuRenderer* GpuRenderer(PrintConsole* con)
|
||||||
|
{
|
||||||
|
return (struct GpuRenderer*)con->renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GpuRenderer_destroy(struct GpuRenderer* r)
|
||||||
|
{
|
||||||
|
// Make sure the queue is idle before destroying anything
|
||||||
|
dkQueueWaitIdle(r->queue);
|
||||||
|
|
||||||
|
// Destroy all the resources we've created
|
||||||
|
dkQueueDestroy(r->queue);
|
||||||
|
dkCmdBufDestroy(r->cmdbuf);
|
||||||
|
dkSwapchainDestroy(r->swapchain);
|
||||||
|
dkMemBlockDestroy(r->dataMemBlock);
|
||||||
|
dkMemBlockDestroy(r->codeMemBlock);
|
||||||
|
dkMemBlockDestroy(r->imageMemBlock);
|
||||||
|
dkDeviceDestroy(r->device);
|
||||||
|
|
||||||
|
// Clear out all state
|
||||||
|
memset(&r->initialized, 0, sizeof(*r) - offsetof(struct GpuRenderer, initialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple function for loading a shader from the filesystem
|
||||||
|
static void GpuRenderer_loadShader(struct GpuRenderer* r, DkShader* pShader, const char* path)
|
||||||
|
{
|
||||||
|
// Open the file, and retrieve its size
|
||||||
|
FILE* f = fopen(path, "rb");
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
uint32_t size = ftell(f);
|
||||||
|
rewind(f);
|
||||||
|
|
||||||
|
// Look for a spot in the code memory block for loading this shader. Note that
|
||||||
|
// we are just using a simple incremental offset; this isn't a general purpose
|
||||||
|
// allocation algorithm.
|
||||||
|
uint32_t codeOffset = r->codeMemOffset;
|
||||||
|
r->codeMemOffset += (size + DK_SHADER_CODE_ALIGNMENT - 1) &~ (DK_SHADER_CODE_ALIGNMENT - 1);
|
||||||
|
|
||||||
|
// Read the file into memory, and close the file
|
||||||
|
fread((uint8_t*)dkMemBlockGetCpuAddr(r->codeMemBlock) + codeOffset, size, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
// Initialize the user provided shader object with the code we've just loaded
|
||||||
|
DkShaderMaker shaderMaker;
|
||||||
|
dkShaderMakerDefaults(&shaderMaker, r->codeMemBlock, codeOffset);
|
||||||
|
dkShaderInitialize(pShader, &shaderMaker);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool GpuRenderer_init(PrintConsole* con)
|
||||||
|
{
|
||||||
|
struct GpuRenderer* r = GpuRenderer(con);
|
||||||
|
|
||||||
|
if (r->initialized) {
|
||||||
|
// We're already initialized
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the deko3d device, which is the root object
|
||||||
|
DkDeviceMaker deviceMaker;
|
||||||
|
dkDeviceMakerDefaults(&deviceMaker);
|
||||||
|
r->device = dkDeviceCreate(&deviceMaker);
|
||||||
|
|
||||||
|
// Create the queue
|
||||||
|
DkQueueMaker queueMaker;
|
||||||
|
dkQueueMakerDefaults(&queueMaker, r->device);
|
||||||
|
queueMaker.flags = DkQueueFlags_Graphics;
|
||||||
|
r->queue = dkQueueCreate(&queueMaker);
|
||||||
|
|
||||||
|
// Calculate required width/height for the framebuffers
|
||||||
|
u32 width = con->font.tileWidth * con->consoleWidth;
|
||||||
|
u32 height = con->font.tileHeight * con->consoleHeight;
|
||||||
|
u32 totalConSize = con->consoleWidth * con->consoleHeight;
|
||||||
|
|
||||||
|
// Calculate layout for the framebuffers
|
||||||
|
DkImageLayoutMaker imageLayoutMaker;
|
||||||
|
dkImageLayoutMakerDefaults(&imageLayoutMaker, r->device);
|
||||||
|
imageLayoutMaker.flags = DkImageFlags_UsageRender | DkImageFlags_UsagePresent | DkImageFlags_HwCompression;
|
||||||
|
imageLayoutMaker.format = DkImageFormat_RGBA8_Unorm;
|
||||||
|
imageLayoutMaker.dimensions[0] = width;
|
||||||
|
imageLayoutMaker.dimensions[1] = height;
|
||||||
|
|
||||||
|
// Calculate layout for the framebuffers
|
||||||
|
DkImageLayout framebufferLayout;
|
||||||
|
dkImageLayoutInitialize(&framebufferLayout, &imageLayoutMaker);
|
||||||
|
|
||||||
|
// Calculate layout for the tileset
|
||||||
|
dkImageLayoutMakerDefaults(&imageLayoutMaker, r->device);
|
||||||
|
imageLayoutMaker.type = DkImageType_2DArray;
|
||||||
|
imageLayoutMaker.format = DkImageFormat_R32_Float;
|
||||||
|
imageLayoutMaker.dimensions[0] = con->font.tileWidth;
|
||||||
|
imageLayoutMaker.dimensions[1] = con->font.tileHeight;
|
||||||
|
imageLayoutMaker.dimensions[2] = con->font.numChars;
|
||||||
|
|
||||||
|
// Calculate layout for the tileset
|
||||||
|
DkImageLayout tilesetLayout;
|
||||||
|
dkImageLayoutInitialize(&tilesetLayout, &imageLayoutMaker);
|
||||||
|
|
||||||
|
// Retrieve necessary size and alignment for the framebuffers
|
||||||
|
uint32_t framebufferSize = dkImageLayoutGetSize(&framebufferLayout);
|
||||||
|
uint32_t framebufferAlign = dkImageLayoutGetAlignment(&framebufferLayout);
|
||||||
|
framebufferSize = (framebufferSize + framebufferAlign - 1) &~ (framebufferAlign - 1);
|
||||||
|
|
||||||
|
// Retrieve necessary size and alignment for the tileset
|
||||||
|
uint32_t tilesetSize = dkImageLayoutGetSize(&tilesetLayout);
|
||||||
|
uint32_t tilesetAlign = dkImageLayoutGetAlignment(&tilesetLayout);
|
||||||
|
tilesetSize = (tilesetSize + tilesetAlign - 1) &~ (tilesetAlign - 1);
|
||||||
|
|
||||||
|
// Create a memory block that will host the framebuffers and the tileset
|
||||||
|
DkMemBlockMaker memBlockMaker;
|
||||||
|
dkMemBlockMakerDefaults(&memBlockMaker, r->device, FB_NUM*framebufferSize + tilesetSize);
|
||||||
|
memBlockMaker.flags = DkMemBlockFlags_GpuCached | DkMemBlockFlags_Image;
|
||||||
|
r->imageMemBlock = dkMemBlockCreate(&memBlockMaker);
|
||||||
|
|
||||||
|
// Initialize the framebuffers with the layout and backing memory we've just created
|
||||||
|
DkImage const* swapchainImages[FB_NUM];
|
||||||
|
for (unsigned i = 0; i < FB_NUM; i ++) {
|
||||||
|
swapchainImages[i] = &r->framebuffers[i];
|
||||||
|
dkImageInitialize(&r->framebuffers[i], &framebufferLayout, r->imageMemBlock, i*framebufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a swapchain out of the framebuffers we've just initialized
|
||||||
|
DkSwapchainMaker swapchainMaker;
|
||||||
|
dkSwapchainMakerDefaults(&swapchainMaker, r->device, nwindowGetDefault(), swapchainImages, FB_NUM);
|
||||||
|
r->swapchain = dkSwapchainCreate(&swapchainMaker);
|
||||||
|
|
||||||
|
// Initialize the tileset
|
||||||
|
dkImageInitialize(&r->tileset, &tilesetLayout, r->imageMemBlock, FB_NUM*framebufferSize);
|
||||||
|
|
||||||
|
// Create a memory block onto which we will load shader code
|
||||||
|
dkMemBlockMakerDefaults(&memBlockMaker, r->device, CODEMEMSIZE);
|
||||||
|
memBlockMaker.flags = DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached | DkMemBlockFlags_Code;
|
||||||
|
r->codeMemBlock = dkMemBlockCreate(&memBlockMaker);
|
||||||
|
r->codeMemOffset = 0;
|
||||||
|
|
||||||
|
// Load our shaders (both vertex and fragment)
|
||||||
|
romfsInit();
|
||||||
|
GpuRenderer_loadShader(r, &r->vertexShader, "romfs:/shaders/console_vsh.dksh");
|
||||||
|
GpuRenderer_loadShader(r, &r->fragmentShader, "romfs:/shaders/console_fsh.dksh");
|
||||||
|
|
||||||
|
// Generate the descriptors
|
||||||
|
struct {
|
||||||
|
DkImageDescriptor images[NUM_IMAGE_SLOTS];
|
||||||
|
DkSamplerDescriptor samplers[NUM_SAMPLER_SLOTS];
|
||||||
|
} descriptors;
|
||||||
|
|
||||||
|
// Generate a image descriptor for the tileset
|
||||||
|
DkImageView tilesetView;
|
||||||
|
dkImageViewDefaults(&tilesetView, &r->tileset);
|
||||||
|
dkImageDescriptorInitialize(&descriptors.images[0], &tilesetView, false, false);
|
||||||
|
|
||||||
|
// Generate a sampler descriptor for the tileset
|
||||||
|
DkSampler sampler;
|
||||||
|
dkSamplerDefaults(&sampler);
|
||||||
|
sampler.wrapMode[0] = DkWrapMode_ClampToEdge;
|
||||||
|
sampler.wrapMode[1] = DkWrapMode_ClampToEdge;
|
||||||
|
sampler.minFilter = DkFilter_Nearest;
|
||||||
|
sampler.magFilter = DkFilter_Nearest;
|
||||||
|
dkSamplerDescriptorInitialize(&descriptors.samplers[0], &sampler);
|
||||||
|
|
||||||
|
uint32_t descriptorsOffset = CMDMEMSIZE;
|
||||||
|
uint32_t configOffset = (descriptorsOffset + sizeof(descriptors) + DK_UNIFORM_BUF_ALIGNMENT - 1) &~ (DK_UNIFORM_BUF_ALIGNMENT - 1);
|
||||||
|
uint32_t configSize = (sizeof(ConsoleConfig) + DK_UNIFORM_BUF_ALIGNMENT - 1) &~ (DK_UNIFORM_BUF_ALIGNMENT - 1);
|
||||||
|
|
||||||
|
uint32_t charBufOffset = configOffset + configSize;
|
||||||
|
uint32_t charBufSize = totalConSize * sizeof(ConsoleChar);
|
||||||
|
|
||||||
|
// Create a memory block which will be used for recording command lists using a command buffer
|
||||||
|
dkMemBlockMakerDefaults(&memBlockMaker, r->device,
|
||||||
|
(charBufOffset + charBufSize + DK_MEMBLOCK_ALIGNMENT - 1) &~ (DK_MEMBLOCK_ALIGNMENT - 1)
|
||||||
|
);
|
||||||
|
memBlockMaker.flags = DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached;
|
||||||
|
r->dataMemBlock = dkMemBlockCreate(&memBlockMaker);
|
||||||
|
|
||||||
|
// Create a command buffer object
|
||||||
|
DkCmdBufMaker cmdbufMaker;
|
||||||
|
dkCmdBufMakerDefaults(&cmdbufMaker, r->device);
|
||||||
|
r->cmdbuf = dkCmdBufCreate(&cmdbufMaker);
|
||||||
|
|
||||||
|
// Feed our memory to the command buffer so that we can start recording commands
|
||||||
|
dkCmdBufAddMemory(r->cmdbuf, r->dataMemBlock, 0, CMDMEMSIZE);
|
||||||
|
|
||||||
|
// Create a temporary buffer that will hold the tileset
|
||||||
|
dkMemBlockMakerDefaults(&memBlockMaker, r->device,
|
||||||
|
(sizeof(float)*con->font.tileWidth*con->font.tileHeight*con->font.numChars + DK_MEMBLOCK_ALIGNMENT - 1) &~ (DK_MEMBLOCK_ALIGNMENT - 1)
|
||||||
|
);
|
||||||
|
memBlockMaker.flags = DkMemBlockFlags_CpuUncached | DkMemBlockFlags_GpuCached;
|
||||||
|
DkMemBlock scratchMemBlock = dkMemBlockCreate(&memBlockMaker);
|
||||||
|
float* scratchMem = (float*)dkMemBlockGetCpuAddr(scratchMemBlock);
|
||||||
|
|
||||||
|
// Unpack 1bpp tileset into a texture image the GPU can read
|
||||||
|
unsigned packedTileWidth = (con->font.tileWidth+7)/8;
|
||||||
|
for (unsigned tile = 0; tile < con->font.numChars; tile ++) {
|
||||||
|
const uint8_t* data = (const uint8_t*)con->font.gfx + con->font.tileHeight*packedTileWidth*tile;
|
||||||
|
for (unsigned y = 0; y < con->font.tileHeight; y ++) {
|
||||||
|
const uint8_t* row = &data[packedTileWidth*(y+1)];
|
||||||
|
uint8_t c = 0;
|
||||||
|
for (unsigned x = 0; x < con->font.tileWidth; x ++) {
|
||||||
|
if (!(x & 7))
|
||||||
|
c = *--row;
|
||||||
|
*scratchMem++ = (c & 0x80) ? 1.0f : 0.0f;
|
||||||
|
c <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up configuration
|
||||||
|
DkGpuAddr configAddr = dkMemBlockGetGpuAddr(r->dataMemBlock) + configOffset;
|
||||||
|
ConsoleConfig consoleConfig = {};
|
||||||
|
consoleConfig.dimensions[0] = width;
|
||||||
|
consoleConfig.dimensions[1] = height;
|
||||||
|
consoleConfig.dimensions[2] = con->consoleWidth;
|
||||||
|
consoleConfig.dimensions[3] = con->consoleHeight;
|
||||||
|
memcpy(consoleConfig.vertices, g_vertexData, sizeof(g_vertexData));
|
||||||
|
memcpy(consoleConfig.palettes, g_paletteData, sizeof(g_paletteData));
|
||||||
|
|
||||||
|
// Generate a temporary command list for uploading stuff and run it
|
||||||
|
DkGpuAddr descriptorSet = dkMemBlockGetGpuAddr(r->dataMemBlock) + descriptorsOffset;
|
||||||
|
DkCopyBuf copySrc = { dkMemBlockGetGpuAddr(scratchMemBlock), 0, 0 };
|
||||||
|
DkImageRect copyDst = { 0, 0, 0, con->font.tileWidth, con->font.tileHeight, con->font.numChars };
|
||||||
|
dkCmdBufPushData(r->cmdbuf, descriptorSet, &descriptors, sizeof(descriptors));
|
||||||
|
dkCmdBufPushConstants(r->cmdbuf, configAddr, configSize, 0, sizeof(consoleConfig), &consoleConfig);
|
||||||
|
dkCmdBufBindImageDescriptorSet(r->cmdbuf, descriptorSet, NUM_IMAGE_SLOTS);
|
||||||
|
dkCmdBufBindSamplerDescriptorSet(r->cmdbuf, descriptorSet + NUM_IMAGE_SLOTS*sizeof(DkImageDescriptor), NUM_SAMPLER_SLOTS);
|
||||||
|
dkCmdBufCopyBufferToImage(r->cmdbuf, ©Src, &tilesetView, ©Dst, 0);
|
||||||
|
dkQueueSubmitCommands(r->queue, dkCmdBufFinishList(r->cmdbuf));
|
||||||
|
dkQueueFlush(r->queue);
|
||||||
|
dkQueueWaitIdle(r->queue);
|
||||||
|
dkCmdBufClear(r->cmdbuf);
|
||||||
|
|
||||||
|
// Destroy the scratch memory block since we don't need it anymore
|
||||||
|
dkMemBlockDestroy(scratchMemBlock);
|
||||||
|
|
||||||
|
// Retrieve the address of the character buffer
|
||||||
|
DkGpuAddr charBufAddr = dkMemBlockGetGpuAddr(r->dataMemBlock) + charBufOffset;
|
||||||
|
r->charBuf = (ConsoleChar*)((uint8_t*)dkMemBlockGetCpuAddr(r->dataMemBlock) + charBufOffset);
|
||||||
|
memset(r->charBuf, 0, charBufSize);
|
||||||
|
|
||||||
|
// Generate a command list for each framebuffer, which will bind each of them as a render target
|
||||||
|
for (unsigned i = 0; i < FB_NUM; i ++) {
|
||||||
|
DkImageView imageView;
|
||||||
|
dkImageViewDefaults(&imageView, &r->framebuffers[i]);
|
||||||
|
dkCmdBufBindRenderTarget(r->cmdbuf, &imageView, NULL);
|
||||||
|
r->cmdsBindFramebuffer[i] = dkCmdBufFinishList(r->cmdbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declare structs that will be used for binding state
|
||||||
|
DkViewport viewport = { 0.0f, 0.0f, (float)width, (float)height, 0.0f, 1.0f };
|
||||||
|
DkScissor scissor = { 0, 0, width, height };
|
||||||
|
DkShader const* shaders[] = { &r->vertexShader, &r->fragmentShader };
|
||||||
|
DkRasterizerState rasterizerState;
|
||||||
|
DkColorState colorState;
|
||||||
|
DkColorWriteState colorWriteState;
|
||||||
|
|
||||||
|
// Initialize state structs with the deko3d defaults
|
||||||
|
dkRasterizerStateDefaults(&rasterizerState);
|
||||||
|
dkColorStateDefaults(&colorState);
|
||||||
|
dkColorWriteStateDefaults(&colorWriteState);
|
||||||
|
|
||||||
|
rasterizerState.fillRectangleEnable = true;
|
||||||
|
colorState.alphaCompareOp = DkCompareOp_Greater;
|
||||||
|
|
||||||
|
// Generate the main rendering command list
|
||||||
|
dkCmdBufSetViewports(r->cmdbuf, 0, &viewport, 1);
|
||||||
|
dkCmdBufSetScissors(r->cmdbuf, 0, &scissor, 1);
|
||||||
|
//dkCmdBufClearColorFloat(r->cmdbuf, 0, DkColorMask_RGBA, 0.125f, 0.294f, 0.478f, 0.0f);
|
||||||
|
dkCmdBufClearColorFloat(r->cmdbuf, 0, DkColorMask_RGBA, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
dkCmdBufBindShaders(r->cmdbuf, DkStageFlag_GraphicsMask, shaders, sizeof(shaders)/sizeof(shaders[0]));
|
||||||
|
dkCmdBufBindRasterizerState(r->cmdbuf, &rasterizerState);
|
||||||
|
dkCmdBufBindColorState(r->cmdbuf, &colorState);
|
||||||
|
dkCmdBufBindColorWriteState(r->cmdbuf, &colorWriteState);
|
||||||
|
dkCmdBufBindUniformBuffer(r->cmdbuf, DkStage_Vertex, 0, configAddr, configSize);
|
||||||
|
dkCmdBufBindTexture(r->cmdbuf, DkStage_Fragment, 0, dkMakeTextureHandle(0, 0));
|
||||||
|
dkCmdBufBindVtxAttribState(r->cmdbuf, g_attribState, sizeof(g_attribState)/sizeof(g_attribState[0]));
|
||||||
|
dkCmdBufBindVtxBufferState(r->cmdbuf, g_vtxbufState, sizeof(g_vtxbufState)/sizeof(g_vtxbufState[0]));
|
||||||
|
dkCmdBufBindVtxBuffer(r->cmdbuf, 0, charBufAddr, charBufSize);
|
||||||
|
dkCmdBufSetAlphaRef(r->cmdbuf, 0.0f);
|
||||||
|
dkCmdBufDraw(r->cmdbuf, DkPrimitive_Triangles, 3, totalConSize, 0, 0);
|
||||||
|
r->cmdsRender = dkCmdBufFinishList(r->cmdbuf);
|
||||||
|
|
||||||
|
r->initialized = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GpuRenderer_deinit(PrintConsole* con)
|
||||||
|
{
|
||||||
|
struct GpuRenderer* r = GpuRenderer(con);
|
||||||
|
|
||||||
|
if (r->initialized) {
|
||||||
|
GpuRenderer_destroy(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GpuRenderer_drawChar(PrintConsole* con, int x, int y, int c)
|
||||||
|
{
|
||||||
|
struct GpuRenderer* r = GpuRenderer(con);
|
||||||
|
|
||||||
|
int writingColor = con->fg;
|
||||||
|
int screenColor = con->bg;
|
||||||
|
|
||||||
|
if (con->flags & CONSOLE_COLOR_BOLD) {
|
||||||
|
writingColor += 8;
|
||||||
|
} else if (con->flags & CONSOLE_COLOR_FAINT) {
|
||||||
|
writingColor += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (con->flags & CONSOLE_COLOR_REVERSE) {
|
||||||
|
int tmp = writingColor;
|
||||||
|
writingColor = screenColor;
|
||||||
|
screenColor = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the fence
|
||||||
|
dkFenceWait(&r->lastRenderFence, UINT64_MAX);
|
||||||
|
|
||||||
|
ConsoleChar* pos = &r->charBuf[y*con->consoleWidth+x];
|
||||||
|
pos->tileId = c;
|
||||||
|
pos->frontPal = writingColor;
|
||||||
|
pos->backPal = screenColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GpuRenderer_scrollWindow(PrintConsole* con)
|
||||||
|
{
|
||||||
|
struct GpuRenderer* r = GpuRenderer(con);
|
||||||
|
|
||||||
|
// Wait for the fence
|
||||||
|
dkFenceWait(&r->lastRenderFence, UINT64_MAX);
|
||||||
|
|
||||||
|
// Perform the scrolling
|
||||||
|
for (int y = 0; y < con->windowHeight-1; y ++) {
|
||||||
|
memcpy(
|
||||||
|
&r->charBuf[(con->windowY+y+0)*con->consoleWidth + con->windowX],
|
||||||
|
&r->charBuf[(con->windowY+y+1)*con->consoleWidth + con->windowX],
|
||||||
|
sizeof(ConsoleChar)*con->windowWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GpuRenderer_flushAndSwap(PrintConsole* con)
|
||||||
|
{
|
||||||
|
struct GpuRenderer* r = GpuRenderer(con);
|
||||||
|
|
||||||
|
// Acquire a framebuffer from the swapchain (and wait for it to be available)
|
||||||
|
int slot = dkQueueAcquireImage(r->queue, r->swapchain);
|
||||||
|
|
||||||
|
// Run the command list that binds said framebuffer as a render target
|
||||||
|
dkQueueSubmitCommands(r->queue, r->cmdsBindFramebuffer[slot]);
|
||||||
|
|
||||||
|
// Run the main rendering command list
|
||||||
|
dkQueueSubmitCommands(r->queue, r->cmdsRender);
|
||||||
|
|
||||||
|
// Signal the fence
|
||||||
|
dkQueueSignalFence(r->queue, &r->lastRenderFence, false);
|
||||||
|
|
||||||
|
// Now that we are done rendering, present it to the screen
|
||||||
|
dkQueuePresentImage(r->queue, r->swapchain, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct GpuRenderer s_gpuRenderer =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
GpuRenderer_init,
|
||||||
|
GpuRenderer_deinit,
|
||||||
|
GpuRenderer_drawChar,
|
||||||
|
GpuRenderer_scrollWindow,
|
||||||
|
GpuRenderer_flushAndSwap,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ConsoleRenderer* getDefaultConsoleRenderer(void)
|
||||||
|
{
|
||||||
|
return &s_gpuRenderer.base;
|
||||||
|
}
|
@ -19,8 +19,8 @@ namespace haze {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/* Allow 20MiB for use by libnx. */
|
/* Allow 30MiB for use by libnx. */
|
||||||
static constexpr size_t LibnxReservedMemorySize = 20_MB;
|
static constexpr size_t LibnxReservedMemorySize = 30_MB;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,12 @@ namespace haze {
|
|||||||
R_CATCH(haze::ResultInvalidPropertyValue) {
|
R_CATCH(haze::ResultInvalidPropertyValue) {
|
||||||
R_TRY(this->WriteResponse(PtpResponseCode_MtpInvalidObjectPropValue));
|
R_TRY(this->WriteResponse(PtpResponseCode_MtpInvalidObjectPropValue));
|
||||||
}
|
}
|
||||||
|
R_CATCH(haze::ResultGroupSpecified) {
|
||||||
|
R_TRY(this->WriteResponse(PtpResponseCode_MtpSpecificationByGroupUnsupported));
|
||||||
|
}
|
||||||
|
R_CATCH(haze::ResultDepthSpecified) {
|
||||||
|
R_TRY(this->WriteResponse(PtpResponseCode_MtpSpecificationByDepthUnsupported));
|
||||||
|
}
|
||||||
R_CATCH(haze::ResultInvalidArgument) {
|
R_CATCH(haze::ResultInvalidArgument) {
|
||||||
R_TRY(this->WriteResponse(PtpResponseCode_GeneralError));
|
R_TRY(this->WriteResponse(PtpResponseCode_GeneralError));
|
||||||
}
|
}
|
||||||
@ -134,6 +140,7 @@ namespace haze {
|
|||||||
case PtpOperationCode_MtpGetObjectPropDesc: R_RETURN(this->GetObjectPropDesc(dp)); break;
|
case PtpOperationCode_MtpGetObjectPropDesc: R_RETURN(this->GetObjectPropDesc(dp)); break;
|
||||||
case PtpOperationCode_MtpGetObjectPropValue: R_RETURN(this->GetObjectPropValue(dp)); break;
|
case PtpOperationCode_MtpGetObjectPropValue: R_RETURN(this->GetObjectPropValue(dp)); break;
|
||||||
case PtpOperationCode_MtpSetObjectPropValue: R_RETURN(this->SetObjectPropValue(dp)); break;
|
case PtpOperationCode_MtpSetObjectPropValue: R_RETURN(this->SetObjectPropValue(dp)); break;
|
||||||
|
case PtpOperationCode_MtpGetObjPropList: R_RETURN(this->GetObjectPropList(dp)); break;
|
||||||
case PtpOperationCode_AndroidGetPartialObject64: R_RETURN(this->GetPartialObject64(dp)); break;
|
case PtpOperationCode_AndroidGetPartialObject64: R_RETURN(this->GetPartialObject64(dp)); break;
|
||||||
case PtpOperationCode_AndroidSendPartialObject: R_RETURN(this->SendPartialObject(dp)); break;
|
case PtpOperationCode_AndroidSendPartialObject: R_RETURN(this->SendPartialObject(dp)); break;
|
||||||
case PtpOperationCode_AndroidTruncateObject: R_RETURN(this->TruncateObject(dp)); break;
|
case PtpOperationCode_AndroidTruncateObject: R_RETURN(this->TruncateObject(dp)); break;
|
||||||
|
@ -113,9 +113,6 @@ namespace haze {
|
|||||||
R_TRY(dp.Read(std::addressof(property_code)));
|
R_TRY(dp.Read(std::addressof(property_code)));
|
||||||
R_TRY(dp.Finalize());
|
R_TRY(dp.Finalize());
|
||||||
|
|
||||||
/* Disallow renaming the storage root. */
|
|
||||||
R_UNLESS(object_id != StorageId_SdmcFs, haze::ResultInvalidObjectId());
|
|
||||||
|
|
||||||
/* Ensure we have a valid property code before continuing. */
|
/* Ensure we have a valid property code before continuing. */
|
||||||
R_UNLESS(IsSupportedObjectPropertyCode(property_code), haze::ResultUnknownPropertyCode());
|
R_UNLESS(IsSupportedObjectPropertyCode(property_code), haze::ResultUnknownPropertyCode());
|
||||||
|
|
||||||
@ -198,6 +195,147 @@ namespace haze {
|
|||||||
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
|
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result PtpResponder::GetObjectPropList(PtpDataParser &dp) {
|
||||||
|
u32 object_id;
|
||||||
|
u32 object_format;
|
||||||
|
s32 property_code;
|
||||||
|
s32 group_code;
|
||||||
|
s32 depth;
|
||||||
|
|
||||||
|
R_TRY(dp.Read(std::addressof(object_id)));
|
||||||
|
R_TRY(dp.Read(std::addressof(object_format)));
|
||||||
|
R_TRY(dp.Read(std::addressof(property_code)));
|
||||||
|
R_TRY(dp.Read(std::addressof(group_code)));
|
||||||
|
R_TRY(dp.Read(std::addressof(depth)));
|
||||||
|
R_TRY(dp.Finalize());
|
||||||
|
|
||||||
|
/* Ensure format is unspecified. */
|
||||||
|
R_UNLESS(object_format == 0, haze::ResultInvalidArgument());
|
||||||
|
|
||||||
|
/* Ensure we have a valid property code. */
|
||||||
|
R_UNLESS(property_code == -1 || IsSupportedObjectPropertyCode(PtpObjectPropertyCode(property_code)), haze::ResultUnknownPropertyCode());
|
||||||
|
|
||||||
|
/* Ensure group code is the default. */
|
||||||
|
R_UNLESS(group_code == PtpPropertyGroupCode_Default, haze::ResultGroupSpecified());
|
||||||
|
|
||||||
|
/* Ensure depth is 0. */
|
||||||
|
R_UNLESS(depth == 0, haze::ResultDepthSpecified());
|
||||||
|
|
||||||
|
/* Check if we know about the object. If we don't, it's an error. */
|
||||||
|
auto * const obj = m_object_database.GetObjectById(object_id);
|
||||||
|
R_UNLESS(obj != nullptr, haze::ResultInvalidObjectId());
|
||||||
|
|
||||||
|
/* Define helper for getting the object type. */
|
||||||
|
const auto GetObjectType = [&] (FsDirEntryType *out_entry_type) {
|
||||||
|
R_RETURN(m_fs.GetEntryType(obj->GetName(), out_entry_type));
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Define helper for getting the object size. */
|
||||||
|
const auto GetObjectSize = [&] (s64 *out_size) {
|
||||||
|
*out_size = 0;
|
||||||
|
|
||||||
|
/* Check if this is a directory. */
|
||||||
|
FsDirEntryType entry_type;
|
||||||
|
R_TRY(GetObjectType(std::addressof(entry_type)));
|
||||||
|
|
||||||
|
/* If it is, we're done. */
|
||||||
|
R_SUCCEED_IF(entry_type == FsDirEntryType_Dir);
|
||||||
|
|
||||||
|
/* Otherwise, open as a file. */
|
||||||
|
FsFile file;
|
||||||
|
R_TRY(m_fs.OpenFile(obj->GetName(), FsOpenMode_Read, std::addressof(file)));
|
||||||
|
|
||||||
|
/* Ensure we maintain a clean state on exit. */
|
||||||
|
ON_SCOPE_EXIT { m_fs.CloseFile(std::addressof(file)); };
|
||||||
|
|
||||||
|
R_RETURN(m_fs.GetFileSize(std::addressof(file), out_size));
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Define helper for determining if the property should be included. */
|
||||||
|
const auto ShouldIncludeProperty = [&] (PtpObjectPropertyCode code) {
|
||||||
|
/* If all properties were requested, or it was the requested property, we should include the property. */
|
||||||
|
return property_code == -1 || code == property_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Determine how many output elements we will report. */
|
||||||
|
u32 num_output_elements = 0;
|
||||||
|
for (const auto obj_property : SupportedObjectProperties) {
|
||||||
|
if (ShouldIncludeProperty(obj_property)) {
|
||||||
|
num_output_elements++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Begin writing the requested object properties. */
|
||||||
|
PtpDataBuilder db(m_buffers->usb_bulk_write_buffer, std::addressof(m_usb_server));
|
||||||
|
|
||||||
|
R_TRY(db.WriteVariableLengthData(m_request_header, [&] {
|
||||||
|
/* Report the number of elements. */
|
||||||
|
R_TRY(db.Add(num_output_elements));
|
||||||
|
|
||||||
|
for (const auto obj_property : SupportedObjectProperties) {
|
||||||
|
if (!ShouldIncludeProperty(obj_property)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the object handle. */
|
||||||
|
R_TRY(db.Add<u32>(object_id));
|
||||||
|
|
||||||
|
/* Write the property code. */
|
||||||
|
R_TRY(db.Add<u16>(obj_property));
|
||||||
|
|
||||||
|
/* Write the property value. */
|
||||||
|
switch (obj_property) {
|
||||||
|
case PtpObjectPropertyCode_PersistentUniqueObjectIdentifier:
|
||||||
|
{
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U128));
|
||||||
|
R_TRY(db.Add<u128>(object_id));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_ObjectSize:
|
||||||
|
{
|
||||||
|
s64 size;
|
||||||
|
R_TRY(GetObjectSize(std::addressof(size)));
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U64));
|
||||||
|
R_TRY(db.Add<u64>(size));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_StorageId:
|
||||||
|
{
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U32));
|
||||||
|
R_TRY(db.Add(StorageId_SdmcFs));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_ParentObject:
|
||||||
|
{
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U32));
|
||||||
|
R_TRY(db.Add(obj->GetParentId()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_ObjectFormat:
|
||||||
|
{
|
||||||
|
FsDirEntryType entry_type;
|
||||||
|
R_TRY(GetObjectType(std::addressof(entry_type)));
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_U16));
|
||||||
|
R_TRY(db.Add(entry_type == FsDirEntryType_File ? PtpObjectFormatCode_Undefined : PtpObjectFormatCode_Association));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PtpObjectPropertyCode_ObjectFileName:
|
||||||
|
{
|
||||||
|
R_TRY(db.Add(PtpDataTypeCode_String));
|
||||||
|
R_TRY(db.AddString(std::strrchr(obj->GetName(), '/') + 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
HAZE_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}));
|
||||||
|
|
||||||
|
/* Write the success response. */
|
||||||
|
R_RETURN(this->WriteResponse(PtpResponseCode_Ok));
|
||||||
|
}
|
||||||
|
|
||||||
Result PtpResponder::SetObjectPropValue(PtpDataParser &rdp) {
|
Result PtpResponder::SetObjectPropValue(PtpDataParser &rdp) {
|
||||||
u32 object_id;
|
u32 object_id;
|
||||||
PtpObjectPropertyCode property_code;
|
PtpObjectPropertyCode property_code;
|
||||||
|
@ -191,6 +191,7 @@ namespace haze {
|
|||||||
R_TRY(usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_High, std::addressof(device_descriptor)));
|
R_TRY(usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_High, std::addressof(device_descriptor)));
|
||||||
|
|
||||||
device_descriptor.bcdUSB = 0x0300;
|
device_descriptor.bcdUSB = 0x0300;
|
||||||
|
device_descriptor.bMaxPacketSize0 = 0x09;
|
||||||
R_TRY(usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Super, std::addressof(device_descriptor)));
|
R_TRY(usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Super, std::addressof(device_descriptor)));
|
||||||
|
|
||||||
/* Binary Object Store */
|
/* Binary Object Store */
|
||||||
|
Loading…
Reference in New Issue
Block a user