--- /dev/null
+#---------------------------------------------------------------------------------
+.SUFFIXES:
+#---------------------------------------------------------------------------------
+
+ifeq ($(strip $(DEVKITARM)),)
+$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
+endif
+
+ifeq ($(strip $(CTRULIB)),)
+# THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru
+$(error "Please set CTRULIB in your environment. export CTRULIB=<path to>libctru")
+endif
+
+TOPDIR ?= $(CURDIR)
+include $(DEVKITARM)/3ds_rules
+
+#---------------------------------------------------------------------------------
+# TARGET is the name of the output
+# BUILD is the directory where object files & intermediate files will be placed
+# 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
+#
+# 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):
+# - <Project name>.png
+# - icon.png
+# - <libctru folder>/default_icon.png
+#---------------------------------------------------------------------------------
+TARGET := $(notdir $(CURDIR))
+BUILD := build
+SOURCES := source
+DATA := data
+INCLUDES := include
+
+#---------------------------------------------------------------------------------
+# options for code generation
+#---------------------------------------------------------------------------------
+ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp
+
+CFLAGS := -g -Wall -O2 -mword-relocations \
+ -fomit-frame-pointer -ffast-math \
+ $(ARCH)
+
+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,$(notdir $*.map)
+
+LIBS := -lctru -lm
+
+#---------------------------------------------------------------------------------
+# list of directories containing libraries, this must be the top level containing
+# 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)
+
+export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
+ $(foreach dir,$(DATA),$(CURDIR)/$(dir))
+
+export DEPSDIR := $(CURDIR)/$(BUILD)
+
+CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
+CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
+SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
+BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
+
+#---------------------------------------------------------------------------------
+# use CXX for linking C++ projects, CC for standard C
+#---------------------------------------------------------------------------------
+ifeq ($(strip $(CPPFILES)),)
+#---------------------------------------------------------------------------------
+ export LD := $(CC)
+#---------------------------------------------------------------------------------
+else
+#---------------------------------------------------------------------------------
+ export LD := $(CXX)
+#---------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------
+
+export OFILES := $(addsuffix .o,$(BINFILES)) \
+ $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
+
+export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
+ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \
+ -I$(CURDIR)/$(BUILD)
+
+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
+
+.PHONY: $(BUILD) clean all
+
+#---------------------------------------------------------------------------------
+all: $(BUILD)
+
+$(BUILD):
+ @[ -d $@ ] || mkdir -p $@
+ @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
+
+#---------------------------------------------------------------------------------
+clean:
+ @echo clean ...
+ @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf
+
+
+#---------------------------------------------------------------------------------
+else
+
+DEPENDS := $(OFILES:.o=.d)
+
+#---------------------------------------------------------------------------------
+# main targets
+#---------------------------------------------------------------------------------
+ifeq ($(strip $(NO_SMDH)),)
+.PHONY: all
+all : $(OUTPUT).3dsx $(OUTPUT).smdh
+endif
+$(OUTPUT).3dsx : $(OUTPUT).elf
+$(OUTPUT).elf : $(OFILES)
+
+#---------------------------------------------------------------------------------
+# you need a rule like this for each extension you use as binary data
+#---------------------------------------------------------------------------------
+%.bin.o : %.bin
+#---------------------------------------------------------------------------------
+ @echo $(notdir $<)
+ @$(bin2o)
+
+# 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 | $(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
+#---------------------------------------------------------------------------------------
--- /dev/null
+This example is for using New3DS MVD, for hardware color-format conversion + video processing(the latter is not supported by ctrulib/this example yet).
--- /dev/null
+#ifndef COSTABLE_H
+#define COSTABLE_H
+
+s32 costable[] = {4096, 4095, 4094, 4093, 4091, 4088, 4084, 4080, 4076, 4071, 4065, 4058, 4051, 4044, 4035, 4026, 4017, 4007, 3996, 3985, 3973, 3960, 3947, 3934, 3919, 3904, 3889, 3873, 3856, 3839, 3821, 3803, 3784, 3765, 3744, 3724, 3703, 3681, 3659, 3636, 3612, 3588, 3564, 3539, 3513, 3487, 3461, 3434, 3406, 3378, 3349, 3320, 3290, 3260, 3229, 3198, 3167, 3135, 3102, 3069, 3035, 3002, 2967, 2932, 2897, 2861, 2825, 2788, 2751, 2714, 2676, 2638, 2599, 2560, 2521, 2481, 2441, 2401, 2360, 2318, 2277, 2235, 2193, 2150, 2107, 2064, 2020, 1976, 1932, 1888, 1843, 1798, 1753, 1707, 1662, 1616, 1569, 1523, 1476, 1429, 1382, 1334, 1287, 1239, 1191, 1143, 1095, 1046, 997, 949, 900, 851, 801, 752, 703, 653, 603, 554, 504, 454, 404, 354, 304, 254, 204, 153, 103, 53, 3, -46, -97, -147, -197, -247, -297, -347, -398, -448, -497, -547, -597, -647, -696, -746, -795, -844, -893, -942, -991, -1040, -1088, -1137, -1185, -1233, -1281, -1328, -1376, -1423, -1470, -1517, -1563, -1610, -1656, -1701, -1747, -1792, -1837, -1882, -1927, -1971, -2015, -2058, -2102, -2144, -2187, -2229, -2271, -2313, -2354, -2395, -2436, -2476, -2516, -2555, -2594, -2633, -2671, -2709, -2747, -2784, -2820, -2857, -2892, -2928, -2963, -2997, -3031, -3065, -3098, -3130, -3163, -3194, -3225, -3256, -3286, -3316, -3345, -3374, -3402, -3430, -3457, -3484, -3510, -3536, -3561, -3585, -3609, -3633, -3656, -3678, -3700, -3721, -3742, -3762, -3782, -3801, -3819, -3837, -3854, -3871, -3887, -3902, -3917, -3932, -3946, -3959, -3971, -3983, -3995, -4005, -4016, -4025, -4034, -4042, -4050, -4057, -4064, -4070, -4075, -4080, -4084, -4087, -4090, -4092, -4094, -4095, -4095, -4095, -4094, -4093, -4091, -4088, -4085, -4081, -4076, -4071, -4066, -4059, -4052, -4045, -4036, -4028, -4018, -4008, -3997, -3986, -3974, -3962, -3949, -3935, -3921, -3906, -3891, -3875, -3858, -3841, -3824, -3805, -3787, -3767, -3747, -3727, -3705, -3684, -3662, -3639, -3615, -3592, -3567, -3542, -3517, -3491, -3464, -3437, -3409, -3381, -3353, -3324, -3294, -3264, -3233, -3202, -3171, -3139, -3106, -3073, -3040, -3006, -2972, -2937, -2902, -2866, -2830, -2793, -2756, -2719, -2681, -2643, -2604, -2565, -2526, -2486, -2446, -2406, -2365, -2324, -2282, -2240, -2198, -2156, -2113, -2069, -2026, -1982, -1938, -1894, -1849, -1804, -1759, -1713, -1668, -1622, -1575, -1529, -1482, -1435, -1388, -1341, -1293, -1245, -1197, -1149, -1101, -1052, -1004, -955, -906, -857, -808, -758, -709, -660, -610, -560, -510, -460, -411, -360, -310, -260, -210, -160, -110, -60, -9, 40, 90, 140, 191, 241, 291, 341, 391, 441, 491, 541, 591, 640, 690, 739, 789, 838, 887, 936, 985, 1033, 1082, 1130, 1179, 1227, 1274, 1322, 1370, 1417, 1464, 1511, 1557, 1604, 1650, 1695, 1741, 1786, 1831, 1876, 1921, 1965, 2009, 2053, 2096, 2139, 2182, 2224, 2266, 2308, 2349, 2390, 2431, 2471, 2511, 2550, 2589, 2628, 2666, 2704, 2742, 2779, 2816, 2852, 2888, 2923, 2958, 2993, 3027, 3060, 3093, 3126, 3158, 3190, 3221, 3252, 3282, 3312, 3342, 3370, 3399, 3426, 3454, 3480, 3507, 3532, 3557, 3582, 3606, 3630, 3653, 3675, 3697, 3718, 3739, 3759, 3779, 3798, 3817, 3835, 3852, 3869, 3885, 3900, 3915, 3930, 3944, 3957, 3970, 3982, 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4063, 4069, 4074, 4079, 4083, 4087, 4090, 4092, 4094, 4095};
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <3ds.h>
+
+#include "costable.h"
+
+u8* inaddr;
+u8* outaddr;
+
+char logstring[256];
+
+s32 pcCos(u16 v)
+{
+ return costable[v&0x1FF];
+}
+
+void printstring(char *str)//Placeholder until ctrulib itself has proper text drawing.
+{
+ strncat(logstring, str, sizeof(logstring)-1);
+}
+
+void draw_startup()
+{
+ Result ret;
+
+ FILE *f = NULL;
+
+ u8* bufAdr = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL);
+ u8* gfxtopadr = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL);
+
+ mvdstdConfig config;
+
+ char str[256];
+
+ int i, j;
+ u32 cnt=0;
+ for(i=0;i<320;i++)
+ {
+ for(j=0;j<240;j++)
+ {
+ u32 v=(j+i*240)*3;
+ bufAdr[v]=(pcCos(i+cnt)+4096)/32;
+ bufAdr[v+1]=(pcCos(j-256+cnt)+4096)/64;
+ bufAdr[v+2]=(pcCos(i+128-cnt)+4096)/32;
+ }
+ }
+
+ f = fopen("sdmc:/mvd_indata.bin", "r");
+ if(f)
+ {
+ fread(inaddr, 1, 0x46500, f);
+ fclose(f);
+ }
+ else
+ {
+ memcpy(inaddr, bufAdr, 320*240*3);
+ }
+
+ memset(gfxtopadr, 0, 0x46500);
+ GSPGPU_FlushDataCache(NULL, inaddr, 0x46500);
+
+ printstring("mvd example\n");
+
+ ret = mvdstdInit(MVDMODE_COLORFORMATCONV, MVDTYPEIN_YUYV422, MVDTYPEOUT_RGB565, 0);
+ memset(str, 0, 256);
+ snprintf(str, sizeof(str)-1, "mvdstdInit(): 0x%08x\n", (unsigned int)ret);
+ printstring(str);
+
+ if(ret>=0)
+ {
+ mvdstdGenerateDefaultConfig(&config, 320, 240, 320, 240, (u32*)inaddr, (u32*)outaddr, (u32*)&outaddr[0x12c00]);
+
+ ret = mvdstdProcessFrame(&config, NULL, 0, 0);
+ memset(str, 0, 256);
+ snprintf(str, sizeof(str)-1, "mvdstdProcessFrame(): 0x%08x\n", (unsigned int)ret);
+ printstring(str);
+ }
+
+ svcSleepThread(1000000000);//Not sure how to determine when frame processing finishes.
+
+ GSPGPU_InvalidateDataCache(NULL, outaddr, 0x100000);
+
+ f = fopen("sdmc:/mvd_outdata.bin", "w");
+ if(f)
+ {
+ fwrite(outaddr, 1, 0x100000, f);
+ fclose(f);
+ }
+
+ f = fopen("sdmc:/mvd_log", "w");
+ if(f)
+ {
+ fwrite(logstring, 1, strlen(logstring), f);
+ fclose(f);
+ }
+
+ memcpy(gfxtopadr, outaddr, 0x46500);
+
+ mvdstdShutdown();
+
+ gfxFlushBuffers();
+ gfxSwapBuffers();
+ gspWaitForVBlank();
+}
+
+int main()
+{
+ // Initialize services
+ srvInit();
+ aptInit();
+ hidInit(NULL);
+ gfxInit();
+ fsInit();
+ sdmcInit();
+ //gfxSet3D(true); // uncomment if using stereoscopic 3D
+
+ memset(logstring, 0, 256);
+
+ inaddr = linearAlloc(0x100000);
+ outaddr = linearAlloc(0x100000);
+
+ if(inaddr && outaddr)
+ {
+ memset(inaddr, 0, 0x100000);
+ memset(outaddr, 0, 0x100000);
+ draw_startup();
+ }
+
+ // Main loop
+ while (aptMainLoop())
+ {
+ gspWaitForVBlank();
+ hidScanInput();
+
+ // Your code goes here
+
+ u32 kDown = hidKeysDown();
+ if (kDown & KEY_START)
+ break; // break in order to return to hbmenu
+ }
+
+ if(inaddr)linearFree(inaddr);
+ if(outaddr)linearFree(outaddr);
+
+ // Exit services
+ sdmcExit();
+ fsExit();
+ gfxExit();
+ hidExit();
+ aptExit();
+ srvExit();
+ return 0;
+}
+
//New3DS-only, see also: http://3dbrew.org/wiki/MVD_Services
typedef enum {
- MVDTYPE_COLORFORMATCONV = 0x00010001,
- MVDTYPE_H264 = 0x00020001
-} mvdstdType;
+ MVDMODE_COLORFORMATCONV,
+ MVDMODE_VIDEOPROCESSING
+} mvdstdMode;
+
+typedef enum {
+ MVDTYPEIN_YUYV422 = 0x00010001,
+ MVDTYPEIN_H264 = 0x00020001
+} mvdstdTypeInput;
+
+typedef enum {
+ MVDTYPEOUT_RGB565 = 0x00040002
+} mvdstdTypeOutput;
typedef struct {
- mvdstdType type;
+ mvdstdTypeInput input_type;
u32 unk_x04;
u32 unk_x08;
- u32 width0, height0;
+ u32 inwidth, inheight;
u32 physaddr_colorconv_indata;
u32 unk_x18[0x28>>2];
u32 flag_x40;//0x0 for colorconv, 0x1 for H.264
u32 unk_x44;
u32 unk_x48;
- u32 height1, width1;//Only set for H.264.
+ u32 outheight0, outwidth0;//Only set for H.264.
u32 unk_x54;
- u32 unk_x58;
- u32 width2, height2;
+ mvdstdTypeOutput output_type;
+ u32 outwidth1, outheight1;
u32 physaddr_outdata0;
u32 physaddr_outdata1_colorconv;
u32 unk_x6c[0xb0>>2];
} mvdstdConfig;
-void mvdstdGenerateDefaultConfig(mvdstdConfig *config, u32 width, u32 height, u32 *vaddr_colorconv_indata, u32 *vaddr_outdata0, u32 *vaddr_outdata1_colorconv);
+void mvdstdGenerateDefaultConfig(mvdstdConfig *config, u32 input_width, u32 input_height, u32 output_width, u32 output_height, u32 *vaddr_colorconv_indata, u32 *vaddr_outdata0, u32 *vaddr_outdata1_colorconv);
-Result mvdstdInit(mvdstdType type, u32 size);//The input size isn't used when type==MVDTYPE_COLORFORMATCONV. H.264 isn't supported currently.
+Result mvdstdInit(mvdstdMode mode, mvdstdTypeInput input_type, mvdstdTypeOutput output_type, u32 size);//The input size isn't used when type==MVDTYPE_COLORFORMATCONV. Video processing / H.264 isn't supported currently.
Result mvdstdShutdown();
Result mvdstdSetConfig(mvdstdConfig *config);
Handle mvdstdHandle;
static u32 mvdstdInitialized = 0;
-static mvdstdType mvdstd_type;
+static mvdstdMode mvdstd_mode;
+static mvdstdTypeInput mvdstd_input_type;
+static mvdstdTypeOutput mvdstd_output_type;
static u32 *mvdstd_workbuf = NULL;
static size_t mvdstd_workbufsize = 0;
return cmdbuf[1];
}
-void mvdstdGenerateDefaultConfig(mvdstdConfig *config, u32 width, u32 height, u32 *vaddr_colorconv_indata, u32 *vaddr_outdata0, u32 *vaddr_outdata1_colorconv)
+void mvdstdGenerateDefaultConfig(mvdstdConfig *config, u32 input_width, u32 input_height, u32 output_width, u32 output_height, u32 *vaddr_colorconv_indata, u32 *vaddr_outdata0, u32 *vaddr_outdata1_colorconv)
{
memset(config, 0, sizeof(mvdstdConfig));
- config->type = mvdstd_type;
+ config->input_type = mvdstd_input_type;
- config->width0 = width;
- config->height0 = height;
+ config->inwidth = input_width;
+ config->inheight = input_height;
- if(mvdstd_type==MVDTYPE_COLORFORMATCONV)config->physaddr_colorconv_indata = osConvertVirtToPhys((u32)vaddr_colorconv_indata);
+ if(mvdstd_mode==MVDMODE_COLORFORMATCONV)config->physaddr_colorconv_indata = osConvertVirtToPhys((u32)vaddr_colorconv_indata);
- if(mvdstd_type==MVDTYPE_H264)
+ if(mvdstd_mode==MVDMODE_VIDEOPROCESSING)
{
config->flag_x40 = 1;
- config->height1 = height;
- config->width1 = width;
+ config->outheight0 = output_height;
+ config->outwidth0 = output_width;
}
- config->unk_x58 = 0x40002;
+ config->output_type = mvdstd_output_type;
- config->width2 = width;
- config->height2 = height;
+ config->outwidth1 = output_width;
+ config->outheight1 = output_height;
config->physaddr_outdata0 = osConvertVirtToPhys((u32)vaddr_outdata0);
- if(mvdstd_type==MVDTYPE_COLORFORMATCONV)config->physaddr_outdata1_colorconv = osConvertVirtToPhys((u32)vaddr_outdata1_colorconv);
+ if(mvdstd_mode==MVDMODE_COLORFORMATCONV)config->physaddr_outdata1_colorconv = osConvertVirtToPhys((u32)vaddr_outdata1_colorconv);
config->unk_x6c[0] = 0x1;
config->unk_x6c[(0x84-0x6c)>>2] = 0x12a;
config->unk_x6c[(0x114-0x6c)>>2] = 0x100;
}
-Result mvdstdInit(mvdstdType type, u32 size)
+Result mvdstdInit(mvdstdMode mode, mvdstdTypeInput input_type, mvdstdTypeOutput output_type, u32 size)
{
Result ret=0;
if(mvdstdInitialized)return 0;
mvdstd_workbufsize = size;
- mvdstd_type = type;
+ mvdstd_mode = mode;
+ mvdstd_input_type = input_type;
+ mvdstd_output_type = output_type;
- if(type==MVDTYPE_COLORFORMATCONV)mvdstd_workbufsize = 1;
- if(type!=MVDTYPE_COLORFORMATCONV)return -2;//H264 isn't supported atm.
+ if(mvdstd_mode==MVDMODE_COLORFORMATCONV)mvdstd_workbufsize = 1;
+ if(mvdstd_mode!=MVDMODE_COLORFORMATCONV)return -2;//Video processing / H.264 isn't supported atm.
if((ret=srvGetServiceHandle(&mvdstdHandle, "mvd:STD")))return ret;
{
if(!mvdstdInitialized)return 0;
- if(mvdstd_type==MVDTYPE_COLORFORMATCONV)
+ if(mvdstd_mode==MVDMODE_COLORFORMATCONV)
{
mvdstdipc_cmd19();
}
{
Result ret;
+ if(!mvdstdInitialized)return 0;
if(config==NULL)return -1;
- if(mvdstd_type!=MVDTYPE_COLORFORMATCONV)return -2;
+ if(mvdstd_mode!=MVDMODE_COLORFORMATCONV)return -2;
ret = mvdstdSetConfig(config);
if(ret<0)return ret;