From 11a50133af87d09c8f0f6dd771888c6344ec6320 Mon Sep 17 00:00:00 2001 From: Subv Date: Sun, 22 Feb 2015 12:50:24 -0500 Subject: [PATCH] GPU/DisplayTransfer: Added some DisplayTransfer tests --- Makefile | 79 +++++-- source/main.cpp | 2 + source/tests/gpu/displaytransfer.cpp | 339 +++++++++++++++++++++++++++ source/tests/gpu/displaytransfer.h | 9 + source/tests/gpu/gpu.cpp | 14 ++ source/tests/gpu/gpu.h | 7 + 6 files changed, 425 insertions(+), 25 deletions(-) create mode 100644 source/tests/gpu/displaytransfer.cpp create mode 100644 source/tests/gpu/displaytransfer.h create mode 100644 source/tests/gpu/gpu.cpp create mode 100644 source/tests/gpu/gpu.h diff --git a/Makefile b/Makefile index 61f45d3..7d2293e 100644 --- a/Makefile +++ b/Makefile @@ -15,22 +15,30 @@ include $(DEVKITARM)/3ds_rules # SOURCES is a list of directories containing source code # DATA is a list of directories containing data files # INCLUDES is a list of directories containing header files -# SPECS is the directory containing the important build and link files +# +# NO_SMDH: if set to anything, no SMDH file is generated. +# APP_TITLE is the name of the app stored in the SMDH file (Optional) +# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) +# APP_AUTHOR is the author of the app stored in the SMDH file (Optional) +# ICON is the filename of the icon (.png), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .png +# - icon.png +# - /default_icon.png #--------------------------------------------------------------------------------- -export TARGET := $(shell basename $(CURDIR)) +TARGET := $(notdir $(CURDIR)) BUILD := build -SOURCES := source source/common source/tests source/tests/fs source/tests/cpu source/tests/kernel +SOURCES := source source/common source/tests source/tests/fs source/tests/cpu source/tests/kernel source/tests/gpu DATA := data -INCLUDES := source #include - +INCLUDES := source #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -march=armv6k -mtune=mpcore +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -CFLAGS := -g -Wall -O2 -mword-relocations -save-temps \ - -fomit-frame-pointer -ffast-math -mfloat-abi=softfp \ +CFLAGS := -g -Wall -O2 -mword-relocations \ + -fomit-frame-pointer -ffast-math \ $(ARCH) CFLAGS += $(INCLUDE) -DARM11 -D_3DS @@ -38,8 +46,7 @@ CFLAGS += $(INCLUDE) -DARM11 -D_3DS CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 ASFLAGS := -g $(ARCH) -LDFLAGS = -specs=3dsx.specs -g $(ARCH) \ - -Wl,-Map,$(TARGET).map +LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) LIBS := -lctru -lm @@ -48,15 +55,15 @@ LIBS := -lctru -lm # include and lib #--------------------------------------------------------------------------------- LIBDIRS := $(CTRULIB) - - + + #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions #--------------------------------------------------------------------------------- ifneq ($(BUILD),$(notdir $(CURDIR))) #--------------------------------------------------------------------------------- - + export OUTPUT := $(CURDIR)/$(TARGET) export TOPDIR := $(CURDIR) @@ -93,54 +100,76 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.png) + ifneq (,$(findstring $(TARGET).png,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).png + else + ifneq (,$(findstring icon.png,$(icons))) + export APP_ICON := $(TOPDIR)/icon.png + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +ifeq ($(strip $(NO_SMDH)),) + export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh +endif + .PHONY: $(BUILD) clean all - + #--------------------------------------------------------------------------------- all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + #--------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(TARGET).3dsx $(TARGET).elf - - + @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf + + #--------------------------------------------------------------------------------- else - + DEPENDS := $(OFILES:.o=.d) - + #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- +ifeq ($(strip $(NO_SMDH)),) +$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh +else $(OUTPUT).3dsx : $(OUTPUT).elf +endif + $(OUTPUT).elf : $(OFILES) #--------------------------------------------------------------------------------- -# you need a rule like this for each extension you use as binary data +# you need a rule like this for each extension you use as binary data #--------------------------------------------------------------------------------- %.bin.o : %.bin #--------------------------------------------------------------------------------- @echo $(notdir $<) @$(bin2o) -# not the right way to do this +# WARNING: This is not the right way to do this! TODO: Do it right! #--------------------------------------------------------------------------------- %.vsh.o : %.vsh #--------------------------------------------------------------------------------- @echo $(notdir $<) @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin - @bin2s ../$(notdir $<).shbin | arm-none-eabi-as -o $@ + @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h @rm ../$(notdir $<).shbin -include $(DEPENDS) - + #--------------------------------------------------------------------------------------- endif #--------------------------------------------------------------------------------------- diff --git a/source/main.cpp b/source/main.cpp index 05aa1fd..2b63c14 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -5,6 +5,7 @@ #include "tests/fs/fs.h" #include "tests/cpu/cputests.h" #include "tests/kernel/kernel.h" +#include "tests/gpu/gpu.h" static unsigned int test_counter = 0; static TestCaller tests[] = { @@ -12,6 +13,7 @@ static TestCaller tests[] = { CPU::Integer::TestAll, CPU::Memory::TestAll, Kernel::TestAll, + GPU::TestAll }; int main(int argc, char** argv) diff --git a/source/tests/gpu/displaytransfer.cpp b/source/tests/gpu/displaytransfer.cpp new file mode 100644 index 0000000..72c9c1a --- /dev/null +++ b/source/tests/gpu/displaytransfer.cpp @@ -0,0 +1,339 @@ +#include +#include +#include "output.h" +#include "common/scope_exit.h" +#include "common/string_funcs.h" +#include "tests/test.h" +#include "tests/gpu/displaytransfer.h" + +namespace GPU { +namespace DisplayTransfer { + +enum PixelFormat { + IN_RGBA8 = 0 << 8, + IN_RGB8 = 1 << 8, + IN_RGB565 = 2 << 8, + IN_RGB5A1 = 3 << 8, + IN_RGBA4 = 4 << 8, + OUT_RGBA8 = 0 << 12, + OUT_RGB8 = 1 << 12, + OUT_RGB565 = 2 << 12, + OUT_RGB5A1 = 3 << 12, + OUT_RGBA4 = 4 << 12, +}; + +union Dimensions { + struct { + u16 height; + u16 width; + } dims; + u32 raw; + + Dimensions(u16 height, u16 width) { + dims.height = height; + dims.width = width; + } +}; + +static void DisplayTransferAndWait(u32* input, u32* output, Dimensions input_dimensions, Dimensions output_dimensions, u32 flags) { + GSPGPU_FlushDataCache(nullptr, (u8*)input, sizeof(u32)); + GSPGPU_InvalidateDataCache(nullptr, (u8*)output, sizeof(u32)); + Result res = GX_SetDisplayTransfer(nullptr, (u32*)input, input_dimensions.raw, (u32*)output, output_dimensions.raw, flags); + if ((u32)res != 0) { + Log(GFX_BOTTOM, Common::FormatString("Something went wrong: %u\r\n", (u32)res)); + return; + } + gfxFlushBuffers(); + gspWaitForPPF(); +} + +static bool RGBA4_To_RGB5A1(u32* input, u32* output) { + memset(output, 0, 0x4000 * 4); + memset(input, 0, 0x4000 * 4); + + // Test Red Input + *input = 0xF000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA4 | OUT_RGB5A1); + TestEquals(*output, (u32)0xF800); + + // Test Green Input + *input = 0x0F00; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA4 | OUT_RGB5A1); + TestEquals(*output, (u32)0x07C0); + + // Test Blue Input + *input = 0x00F0; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA4 | OUT_RGB5A1); + TestEquals(*output, (u32)0x003E); + + // Test 15 Alpha Input + *input = 0x000F; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA4 | OUT_RGB5A1); + TestEquals(*output, (u32)0x0001); + + // Test 8 Alpha Input + *input = 0x0008; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA4 | OUT_RGB5A1); + TestEquals(*output, (u32)0x0001); + + // Test 7 Alpha Input + *input = 0x0007; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA4 | OUT_RGB5A1); + TestEquals(*output, (u32)0x0000); + return true; +} + +static bool RGB5A1_To_RGBA4(u32* input, u32* output) { + memset(output, 0, 0x4000 * 4); + memset(input, 0, 0x4000 * 4); + + // Test Red Input + *input = 0xF800; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGB5A1 | OUT_RGBA4); + TestEquals(*output, (u32)0xF000); + + // Test Green Input + *input = 0x07C0; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGB5A1 | OUT_RGBA4); + TestEquals(*output, (u32)0x0F00); + + // Test Blue Input + *input = 0x003E; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGB5A1 | OUT_RGBA4); + TestEquals(*output, (u32)0x00F0); + + // Test Alpha Input + *input = 0x0001; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGB5A1 | OUT_RGBA4); + TestEquals(*output, (u32)0x000F); + return true; +} + +static bool RGBA8_To_RGBA8(u32* input, u32* output) { + memset(output, 0, 0x4000 * 4); + memset(input, 0, 0x4000 * 4); + + //Test Red Input + *input = 0xFF000000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA8); + TestEquals(*output, (u32)0xFF000000); + + //Test Green Input + *input = 0x00FF0000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA8); + TestEquals(*output, (u32)0x00FF0000); + + //Test Blue Input + *input = 0x0000FF00; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA8); + TestEquals(*output, (u32)0x0000FF00); + + //Test Alpha Input + *input = 0x000000FF; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA8); + TestEquals(*output, (u32)0x000000FF); + return true; +} + +static bool RGBA8_To_RGB8(u32* input, u32* output) { + memset(output, 0, 0x4000 * 4); + memset(input, 0, 0x4000 * 4); + + //Test Red Input + *input = 0xFF000000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB8); + TestEquals(*output, (u32)0x00FF0000u); + + //Test Green Input + *input = 0x00FF0000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB8); + TestEquals(*output, (u32)0x0000FF00u); + + //Test Blue Input + *input = 0x0000FF00; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB8); + TestEquals(*output, (u32)0x000000FFu); + + //Test Alpha Input + *input = 0x000000FF; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB8); + TestEquals(*output, (u32)0x00000000u); + return true; +} + +static bool RGBA8_To_RGB565(u32* input, u32* output) { + memset(output, 0, 0x4000 * 4); + memset(input, 0, 0x4000 * 4); + + //Test Red Input + *input = 0xFF000000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB565); + TestEquals(*output, (u32)0xF800); + + //Test Green Input + *input = 0x00FF0000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB565); + TestEquals(*output, (u32)0x07E0); + + //Test Blue Input + *input = 0x0000FF00; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB565); + TestEquals(*output, (u32)0x001F); + + //Test Alpha Input + *input = 0x000000FF; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB565); + TestEquals(*output, (u32)0x0000); + return true; +} + +static bool RGBA8_To_RGB5A1(u32* input, u32* output) { + memset(output, 0, 0x4000 * 4); + memset(input, 0, 0x4000 * 4); + + // Test Red Input + *input = 0xFF000000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB5A1); + TestEquals(*output, (u32)0xF800); + + // Test Green Input + *input = 0x00FF0000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB5A1); + TestEquals(*output, (u32)0x07C0); + + // Test Blue Input + *input = 0x0000FF00; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB5A1); + TestEquals(*output, (u32)0x003E); + + // Test 255 Alpha Input + *input = 0x000000FF; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB5A1); + TestEquals(*output, (u32)0x0001); + + // Test 100 Alpha Input + *input = 0x00000064; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB5A1); + TestEquals(*output, (u32)0x0000); + + // Test 127 Alpha Input + *input = 0x0000007F; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB5A1); + TestEquals(*output, (u32)0x0000); + + // Test 128 Alpha Input + *input = 0x00000080; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB5A1); + TestEquals(*output, (u32)0x0001); + + // Test 254 Alpha Input + *input = 0x000000FE; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGB5A1); + TestEquals(*output, (u32)0x0001); + return true; +} + +static bool RGBA8_To_RGBA4(u32* input, u32* output) { + memset(output, 0, 0x4000 * 4); + memset(input, 0, 0x4000 * 4); + + // Test Red Input + *input = 0xFF000000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA4); + TestEquals(*output, (u32)0xF000); + + // Test Green Input + *input = 0x00FF0000; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA4); + TestEquals(*output, (u32)0x0F00); + + // Test Blue Input + *input = 0x0000FF00; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA4); + TestEquals(*output, (u32)0x00F0); + + // Test 255 Alpha Input + *input = 0x000000FF; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA4); + TestEquals(*output, (u32)0x000F); + + // Test 100 Alpha Input + *input = 0x00000064; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA4); + TestEquals(*output, (u32)0x0006); + + // Test 127 Alpha Input + *input = 0x0000007F; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA4); + TestEquals(*output, (u32)0x0007); + + // Test 128 Alpha Input + *input = 0x00000080; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA4); + TestEquals(*output, (u32)0x0008); + + // Test 254 Alpha Input + *input = 0x000000FE; //Input + *output = 0; //Output + DisplayTransferAndWait(input, output, Dimensions(0x80, 0x80), Dimensions(0x80, 0x80), IN_RGBA8 | OUT_RGBA4); + TestEquals(*output, (u32)0x000F); + return true; +} + +void TestAll() { + const std::string tag = "DisplayTransfer"; + + u32* input = (u32*)linearAlloc(0x4000 * 4); + u32* output = (u32*)linearAlloc(0x4000 * 4); + + Test(tag, "RGBA8_To_RGBA8", RGBA8_To_RGBA8(input, output), true); + Test(tag, "RGBA8_To_RGB8", RGBA8_To_RGB8(input, output), true); + Test(tag, "RGBA8_To_RGB565", RGBA8_To_RGB565(input, output), true); + Test(tag, "RGBA8_To_RGB5A1", RGBA8_To_RGB5A1(input, output), true); + Test(tag, "RGBA8_To_RGBA4", RGBA8_To_RGBA4(input, output), true); + Test(tag, "RGB5A1_To_RGBA4", RGB5A1_To_RGBA4(input, output), true); + Test(tag, "RGBA4_To_RGB5A1", RGBA4_To_RGB5A1(input, output), true); + + linearFree(input); + linearFree(output); +} + +} +} \ No newline at end of file diff --git a/source/tests/gpu/displaytransfer.h b/source/tests/gpu/displaytransfer.h new file mode 100644 index 0000000..59dc7df --- /dev/null +++ b/source/tests/gpu/displaytransfer.h @@ -0,0 +1,9 @@ +#pragma once + +namespace GPU { +namespace DisplayTransfer { + +void TestAll(); + +} +} \ No newline at end of file diff --git a/source/tests/gpu/gpu.cpp b/source/tests/gpu/gpu.cpp new file mode 100644 index 0000000..7b08ff7 --- /dev/null +++ b/source/tests/gpu/gpu.cpp @@ -0,0 +1,14 @@ +#include <3ds.h> +#include "tests/gpu/gpu.h" +#include "tests/gpu/displaytransfer.h" + +namespace GPU { + +void TestAll() { + // Initialize GPU + GPU_Init(nullptr); + + DisplayTransfer::TestAll(); +} + +} \ No newline at end of file diff --git a/source/tests/gpu/gpu.h b/source/tests/gpu/gpu.h new file mode 100644 index 0000000..b3eabb8 --- /dev/null +++ b/source/tests/gpu/gpu.h @@ -0,0 +1,7 @@ +#pragma once + +namespace GPU { + +void TestAll(); + +} \ No newline at end of file