DONT USE THIS LIBRARY IF YOU DON'T KNOW HOW TO USE

This commit is contained in:
= 2022-12-23 04:59:41 +01:00
parent 82cf7d95fe
commit 6c76004761
14 changed files with 820 additions and 514 deletions

21
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,21 @@
{
"configurations": [
{
"name": "3ds",
"includePath": [
"${workspaceFolder}/**",
//"C:/devkitpro/libnx/include/**",
"C:/devkitpro/libctru/include/**",
"/opt/devkitpro/libctru/include/**",
//"C:/devkitpro/portlibs/switch/include/**",
"/opt/devkitpro/portlibs/3ds/include/**",
"C:/devkitpro/portlibs/3ds/include/**"
],
"defines": [],
"cStandard": "gnu17",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}

20
3ds.cmake Normal file
View File

@ -0,0 +1,20 @@
#########################################################################################
set(DEVKITPRO $ENV{DEVKITPRO})
set(CMAKE_SYSTEM_NAME "Nintendo 3ds")
set(CMAKE_C_COMPILER "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-gcc")
set(CMAKE_CXX_COMPILER "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-g++")
set(CMAKE_AR "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-gcc-ar" CACHE STRING "")
set(CMAKE_RANLIB "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-gcc-ranlib" CACHE STRING "")
set(CMAKE_ASM_COMPILER "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-gcc")
set(ARCH "-march=armv6k -mtune=mpcore -mfloat-abi=hard -mfpu=vfp -mtp=soft -D__3DS__")
set(CMAKE_C_FLAGS "${ARCH} -Wall -mword-relocations -O3 -fomit-frame-pointer -ffunction-sections -fdata-sections" CACHE STRING "C flags")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -std=gnu++20" CACHE STRING "C++ flags")
set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_FIND_ROOT_PATH ${DEVKITPRO}/devkitARM ${DEVKITPRO}/libctru ${DEVKITARM}/portlibs/3ds)
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available")
link_directories(${DEVKITPRO}/libcrtu/lib ${DEVKITPRO}/portlibs/3ds/lib)
#########################################################################################

14
CMakeLists.txt Normal file
View File

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.22)
project(picasso)
set(CMAKE_EXE_LINKER_FLAGS "-L${DEVKITPRO}/libctru/lib -L${DEVKITPRO}/picaGL/lib -L${DEVKITPRO}/portlibs/3ds/lib -specs=3dsx.specs -Wl,--gc-sections")
include_directories(${DEVKITPRO}/libctru/include ${DEVKITPRO}/picaGL/include ${DEVKITPRO}/portlibs/3ds/include)
add_definitions("-D__3DS__")
enable_language(ASM)
add_library(${PROJECT_NAME} STATIC source/picasso_assembler.cpp source/picasso_library.cpp)
target_include_directories(${PROJECT_NAME} PRIVATE include)

348
compile Executable file
View File

@ -0,0 +1,348 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2018-03-07.03; # UTC
# Copyright (C) 1999-2021 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN* | MSYS*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/* | msys/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

43
example/CMakeLists.txt Normal file
View File

@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.22)
project(linpicasso_sample)
set(CMAKE_EXE_LINKER_FLAGS "-L${DEVKITPRO}/libctru/lib -L${DEVKITPRO}/picaGL/lib -L${DEVKITPRO}/portlibs/3ds/lib -specs=3dsx.specs -Wl,--gc-sections")
include_directories(${DEVKITPRO}/libctru/include ${DEVKITPRO}/picaGL/include ${DEVKITPRO}/portlibs/3ds/include)
add_definitions("-D__3DS__")
set(APP_TITLE "${PROJECT_NAME}")
set(APP_DESCRIPTION "Example of Lib Picasso")
set(APP_AUTHOR "Tobi-D7, tobid7vx")
#set(APP_ICON "${PROJECT_SOURCE_DIR}/app/icon.png")
#set(APP_ROMFS "${PROJECT_SOURCE_DIR}/romfs")
enable_language(ASM)
set(BASE_CTR ON CACHE BOOL "Enable 3ds")
add_subdirectory(../ picasso)
add_executable(${PROJECT_NAME}.elf src/main.cpp)
target_include_directories(${PROJECT_NAME}.elf PRIVATE src ../include)
target_link_libraries(${PROJECT_NAME}.elf citro2d citro3d ctru m picasso)
#"${APP_ICON}"
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.smdh
COMMAND smdhtool --create "${APP_TITLE}" "${APP_DESCRIPTION}" "${APP_AUTHOR}" "/opt/devkitpro/libctru/default_icon.png" ${PROJECT_NAME}.smdh
DEPENDS ${PROJECT_NAME}.elf
)
#--romfs=${APP_ROMFS}
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.3dsx
COMMAND 3dsxtool ${PROJECT_NAME}.elf ${PROJECT_NAME}.3dsx --smdh=${PROJECT_NAME}.smdh
DEPENDS ${PROJECT_NAME}.elf
)
add_custom_target( 3ds ALL
DEPENDS ${PROJECT_NAME}.smdh ${PROJECT_NAME}.3dsx
)

172
example/src/main.cpp Normal file
View File

@ -0,0 +1,172 @@
#include <3ds.h>
#include <citro3d.h>
#include <picasso.hpp>
static const char *const vertShader = R"text(
; Example PICA200 vertex shader
; Uniforms
.fvec projection[4]
; Constants
.constf myconst(0.0, 1.0, -1.0, 0.1)
.constf myconst2(0.3, 0.0, 0.0, 0.0)
.alias zeros myconst.xxxx ; Vector full of zeros
.alias ones myconst.yyyy ; Vector full of ones
; Outputs
.out outpos position
.out outclr color
; Inputs (defined as aliases for convenience)
.alias inpos v0
.alias inclr v1
.proc main
; Force the w component of inpos to be 1.0
mov r0.xyz, inpos
mov r0.w, ones
; outpos = projectionMatrix * inpos
dp4 outpos.x, projection[0], r0
dp4 outpos.y, projection[1], r0
dp4 outpos.z, projection[2], r0
dp4 outpos.w, projection[3], r0
; outclr = inclr
mov outclr, inclr
; We're finished
end
.end
)text";
#define CLEAR_COLOR 0x68B0D8FF
#define DISPLAY_TRANSFER_FLAGS \
(GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
typedef struct { float x, y, z; } vertex;
static const vertex vertex_list[] =
{
{ 200.0f, 200.0f, 0.5f },
{ 100.0f, 40.0f, 0.5f },
{ 300.0f, 40.0f, 0.5f },
};
#define vertex_list_count (sizeof(vertex_list)/sizeof(vertex_list[0]))
static DVLB_s* vshader_dvlb;
static shaderProgram_s program;
static int uLoc_projection;
static C3D_Mtx projection;
static char* vshader_shbin;
static int vshader_shbin_size;
static void* vbo_data;
static void sceneInit(void)
{
// Load the vertex shader, create a shader program and bind it
vshader_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size);
shaderProgramInit(&program);
shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]);
C3D_BindProgram(&program);
// Get the location of the uniforms
uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection");
// Configure attributes for use with the vertex shader
C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
AttrInfo_Init(attrInfo);
AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
AttrInfo_AddFixed(attrInfo, 1); // v1=color
// Set the fixed attribute (color) to solid white
C3D_FixedAttribSet(1, 1.0, 1.0, 1.0, 1.0);
// Compute the projection matrix
Mtx_OrthoTilt(&projection, 0.0, 400.0, 0.0, 240.0, 0.0, 1.0, true);
// Create the VBO (vertex buffer object)
vbo_data = linearAlloc(sizeof(vertex_list));
memcpy(vbo_data, vertex_list, sizeof(vertex_list));
// Configure buffers
C3D_BufInfo* bufInfo = C3D_GetBufInfo();
BufInfo_Init(bufInfo);
BufInfo_Add(bufInfo, vbo_data, sizeof(vertex), 1, 0x0);
// Configure the first fragment shading substage to just pass through the vertex color
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
C3D_TexEnv* env = C3D_GetTexEnv(0);
C3D_TexEnvInit(env);
C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, (GPU_TEVSRC)0, (GPU_TEVSRC)0);
C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
}
static void sceneRender(void)
{
// Update the uniforms
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection);
// Draw the VBO
C3D_DrawArrays(GPU_TRIANGLES, 0, vertex_list_count);
}
static void sceneExit(void)
{
// Free the VBO
linearFree(vbo_data);
// Free the shader program
shaderProgramFree(&program);
DVLB_Free(vshader_dvlb);
}
int main()
{
// Initialize graphics
gfxInitDefault();
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
vshader_shbin = Pica::AssembleCode(vertShader, vshader_shbin_size);
// Initialize the render target
C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
// Initialize the scene
sceneInit();
// Main loop
while (aptMainLoop())
{
hidScanInput();
// Respond to user input
u32 kDown = hidKeysDown();
if (kDown & KEY_START)
break; // break in order to return to hbmenu
// Render the scene
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
C3D_RenderTargetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0);
C3D_FrameDrawOn(target);
sceneRender();
C3D_FrameEnd(0);
}
// Deinitialize the scene
sceneExit();
// Deinitialize graphics
C3D_Fini();
gfxExit();
return 0;
}

9
include/picasso.hpp Normal file
View File

@ -0,0 +1,9 @@
//#pragma once
#include <iostream>
#include <string>
namespace Pica
{
void InstallErrorCallback(void(*ErrorHandler)(const char* top, const char* message));
char* AssembleCode(const char* vertex, int &res_size);
}

View File

@ -1,132 +0,0 @@
#pragma once
#include <stdio.h>
#include "types.h"
class FileClass
{
FILE* f;
bool LittleEndian, own;
int filePos;
size_t _RawRead(void* buffer, size_t size)
{
size_t x = fread(buffer, 1, size, f);
filePos += x;
return x;
}
size_t _RawWrite(const void* buffer, size_t size)
{
size_t x = fwrite(buffer, 1, size, f);
filePos += x;
return x;
}
public:
FileClass(const char* file, const char* mode) : LittleEndian(true), own(true), filePos(0)
{
f = fopen(file, mode);
}
FileClass(FILE* inf) : f(inf), LittleEndian(true), own(false), filePos(0) { }
~FileClass()
{
if (f && own) fclose(f);
}
void SetLittleEndian() { LittleEndian = true; }
void SetBigEndian() { LittleEndian = false; }
FILE* get_ptr() { return f; }
bool openerror() { return f == NULL; }
dword_t ReadDword()
{
dword_t value;
_RawRead(&value, sizeof(dword_t));
return LittleEndian ? le_dword(value) : be_dword(value);
}
void WriteDword(dword_t value)
{
value = LittleEndian ? le_dword(value) : be_dword(value);
_RawWrite(&value, sizeof(dword_t));
}
word_t ReadWord()
{
word_t value;
_RawRead(&value, sizeof(word_t));
return LittleEndian ? le_word(value) : be_word(value);
}
void WriteWord(word_t value)
{
value = LittleEndian ? le_word(value) : be_word(value);
_RawWrite(&value, sizeof(word_t));
}
hword_t ReadHword()
{
hword_t value;
_RawRead(&value, sizeof(hword_t));
return LittleEndian ? le_hword(value) : be_hword(value);
}
void WriteHword(hword_t value)
{
value = LittleEndian ? le_hword(value) : be_hword(value);
_RawWrite(&value, sizeof(hword_t));
}
byte_t ReadByte()
{
byte_t value;
_RawRead(&value, sizeof(byte_t));
return value;
}
void WriteByte(byte_t value)
{
_RawWrite(&value, sizeof(byte_t));
}
float ReadFloat()
{
union { word_t w; float f; } t;
t.w = ReadWord();
return t.f;
}
void WriteFloat(float value)
{
union { word_t w; float f; } t;
t.f = value;
WriteWord(t.w);
}
bool ReadRaw(void* buffer, size_t size) { return _RawRead(buffer, size) == size; }
bool WriteRaw(const void* buffer, size_t size) { return _RawWrite(buffer, size) == size; }
void Seek(int pos, int mode) { fseek(f, pos, mode); }
int Tell() { return filePos /*ftell(f)*/; }
void Flush() { fflush(f); }
};
static inline char* StringFromFile(const char* filename)
{
FILE* f = fopen(filename, "rb");
if (!f) return NULL;
fseek(f, 0, SEEK_END);
int size = ftell(f);
rewind(f);
char* buf = (char*)malloc(size+1);
if (!buf)
{
fclose(f);
return NULL;
}
fread(buf, 1, size, f);
buf[size] = 0;
fclose(f);
return buf;
}

View File

@ -1,57 +0,0 @@
#pragma once
enum
{
MAESTRO_ADD = 0x00,
MAESTRO_DP3,
MAESTRO_DP4,
MAESTRO_DPH,
MAESTRO_DST,
MAESTRO_EX2,
MAESTRO_LG2,
MAESTRO_LITP,
MAESTRO_MUL,
MAESTRO_SGE,
MAESTRO_SLT,
MAESTRO_FLR,
MAESTRO_MAX,
MAESTRO_MIN,
MAESTRO_RCP,
MAESTRO_RSQ,
MAESTRO_unk10,
MAESTRO_unk11,
MAESTRO_MOVA,
MAESTRO_MOV,
MAESTRO_unk14,
MAESTRO_unk15,
MAESTRO_unk16,
MAESTRO_unk17,
MAESTRO_DPHI,
MAESTRO_DSTI,
MAESTRO_SGEI,
MAESTRO_SLTI,
MAESTRO_unk1C,
MAESTRO_unk1D,
MAESTRO_unk1E,
MAESTRO_unk1F,
MAESTRO_BREAK,
MAESTRO_NOP,
MAESTRO_END,
MAESTRO_BREAKC,
MAESTRO_CALL,
MAESTRO_CALLC,
MAESTRO_CALLU,
MAESTRO_IFU,
MAESTRO_IFC,
MAESTRO_FOR,
MAESTRO_EMIT, // Geometry shader related
MAESTRO_SETEMIT, // Geometry shader related
MAESTRO_JMPC,
MAESTRO_JMPU,
MAESTRO_CMP, // only the upper 5 bits are used for the opcode
// Only the upper 3 bits are used for the following opcodes
MAESTRO_MADI = 0x30,
MAESTRO_MAD = 0x38,
};

View File

@ -1,256 +0,0 @@
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <getopt.h>
#ifdef WIN32
#include <fcntl.h>
#endif
#include "types.h"
#include <vector>
#include <list>
#include <map>
#include <string>
#include <algorithm>
#include "FileClass.h"
#include "maestro_opcodes.h"
#if !defined(WIN32) && !defined(stricmp)
#define stricmp strcasecmp
#endif
enum
{
COMP_X = 0,
COMP_Y,
COMP_Z,
COMP_W,
};
#define SWIZZLE_COMP(n,v) ((v) << (6-(n)*2))
#define OPSRC_MAKE(neg, sw) ((neg) | ((sw) << 1))
#define OPDESC_MAKE(out, src1, src2, src3) ((out) | ((src1) << 4) | ((src2) << (4+9)) | ((src3) << (4+9*2)))
#define FMT_OPCODE(n) ((n)<<26)
#define OUTPUT_MAKE(i, reg, mask) ((i) | ((reg)<<16) | ((u64)(mask)<<32))
#define DEFAULT_SWIZZLE (SWIZZLE_COMP(0,COMP_X) | SWIZZLE_COMP(1,COMP_Y) | SWIZZLE_COMP(2,COMP_Z) | SWIZZLE_COMP(3,COMP_W))
#define DEFAULT_OPSRC OPSRC_MAKE(0, DEFAULT_SWIZZLE)
#define OPDESC_MASK_D123 OPDESC_MAKE(0xF, 0x1FF, 0x1FF, 0x1FF)
#define OPDESC_MASK_D12 OPDESC_MAKE(0xF, 0x1FF, 0x1FF, 0)
#define OPDESC_MASK_D1 OPDESC_MAKE(0xF, 0x1FF, 0, 0)
#define OPDESC_MASK_1 OPDESC_MAKE(0, 0x1FF, 0, 0)
#define OPDESC_MASK_12 OPDESC_MAKE(0, 0x1FF, 0x1FF, 0)
enum
{
COND_EQ = 0,
COND_NE,
COND_LT,
COND_LE,
COND_GT,
COND_GE,
};
//-----------------------------------------------------------------------------
// Global data
//-----------------------------------------------------------------------------
// Output buffer
#define MAX_VSH_SIZE 512
typedef std::vector<u32> outputBufType;
typedef outputBufType::iterator outputBufIter;
extern outputBufType g_outputBuf;
enum
{
SE_PROC,
SE_FOR,
SE_IF,
SE_ARRAY,
};
struct StackEntry
{
int type;
size_t pos;
union
{
const char* strExtra;
size_t uExtra;
};
};
// Stack used to keep track of stuff.
#define MAX_STACK 32
extern StackEntry g_stack[MAX_STACK];
extern int g_stackPos;
// Operand descriptor stuff.
#define MAX_OPDESC 128
extern int g_opdescTable[MAX_OPDESC];
extern int g_opdeskMasks[MAX_OPDESC]; // used to keep track of used bits
extern int g_opdescCount;
enum
{
UTYPE_BOOL = 0,
UTYPE_IVEC,
UTYPE_FVEC,
};
struct Uniform
{
std::string name;
int pos, size;
int type;
inline bool operator <(const Uniform& rhs) const
{
return pos < rhs.pos;
}
void init(const char* name, int pos, int size, int type)
{
this->name = name;
this->pos = pos;
this->size = size;
this->type = type;
}
};
// List of uniforms
#define MAX_UNIFORM 0x60
extern Uniform g_uniformTable[MAX_UNIFORM];
extern int g_uniformCount;
struct DVLEData; // Forward declaration
typedef std::pair<size_t, size_t> procedure; // position, size
typedef std::pair<size_t, std::string> relocation; // position, name
typedef std::map<std::string, procedure> procTableType;
typedef std::map<std::string, size_t> labelTableType;
typedef std::map<std::string, int> aliasTableType;
typedef std::vector<relocation> relocTableType;
typedef std::list<DVLEData> dvleTableType;
typedef procTableType::iterator procTableIter;
typedef labelTableType::iterator labelTableIter;
typedef aliasTableType::iterator aliasTableIter;
typedef relocTableType::iterator relocTableIter;
typedef dvleTableType::iterator dvleTableIter;
extern procTableType g_procTable;
extern dvleTableType g_dvleTable;
extern relocTableType g_procRelocTable;
extern int g_totalDvleCount;
// The following are cleared before each file is processed
extern labelTableType g_labels;
extern relocTableType g_labelRelocTable;
extern aliasTableType g_aliases;
extern bool g_autoNop;
int AssembleString(char* str, const char* initialFilename);
int RelocateProduct(void);
//-----------------------------------------------------------------------------
// Local data
//-----------------------------------------------------------------------------
enum
{
OUTTYPE_POS = 0,
OUTTYPE_NQUAT = 1,
OUTTYPE_CLR = 2,
OUTTYPE_TCOORD0 = 3,
OUTTYPE_TCOORD0W = 4,
OUTTYPE_TCOORD1 = 5,
OUTTYPE_TCOORD2 = 6,
OUTTYPE_VIEW = 8,
OUTTYPE_DUMMY = 9,
};
enum
{
GSHTYPE_POINT = 0,
GSHTYPE_VARIABLE = 1,
GSHTYPE_FIXED = 2,
};
struct Constant
{
int regId;
int type;
union
{
float fparam[4];
u8 iparam[4];
bool bparam;
};
};
struct DVLEData
{
// General config
std::string filename;
std::string entrypoint;
size_t entryStart, entryEnd;
bool nodvle, isGeoShader, isCompatGeoShader, isMerge;
u16 inputMask, outputMask;
u8 geoShaderType;
u8 geoShaderFixedStart;
u8 geoShaderVariableNum;
u8 geoShaderFixedNum;
// Uniforms
Uniform uniformTable[MAX_UNIFORM];
int uniformCount;
size_t symbolSize;
// Constants
#define MAX_CONSTANT 0x60
Constant constantTable[MAX_CONSTANT];
int constantCount;
// Outputs
#define MAX_OUTPUT 16
u64 outputTable[MAX_OUTPUT];
u32 outputUsedReg;
int outputCount;
bool usesGshSpace() const { return isGeoShader && !isCompatGeoShader; }
int findFreeOutput() const
{
for (int i = 0; i < maxOutputReg(); i ++)
if (!(outputMask & BIT(i)))
return i;
return -1;
}
int findFreeInput() const
{
for (int i = 0; i < 16; i ++)
if (!(inputMask & BIT(i)))
return i;
return -1;
}
int maxOutputReg() const
{
return isGeoShader ? 0x07 : 0x10;
}
DVLEData(const char* filename) :
filename(filename), entrypoint("main"),
nodvle(false), isGeoShader(false), isCompatGeoShader(false), isMerge(false),
inputMask(0), outputMask(0), geoShaderType(0), geoShaderFixedStart(0), geoShaderVariableNum(0), geoShaderFixedNum(0),
uniformCount(0), symbolSize(0), constantCount(0), outputUsedReg(0), outputCount(0) { }
};

View File

@ -1,4 +1,4 @@
#include "picasso.h"
#include <picasso/picasso.h>
//#define DEBUG
#define BUF g_outputBuf

192
source/picasso_library.cpp Normal file
View File

@ -0,0 +1,192 @@
#include <picasso.hpp>
#include <picasso/picasso.h>
// f24 has:
// - 1 sign bit
// - 7 exponent bits
// - 16 mantissa bits
uint32_t f32tof24(float f) {
uint32_t i;
memcpy(&i, &f, sizeof(f));
uint32_t mantissa = (i << 9) >> 9;
int32_t exponent = (i << 1) >> 24;
uint32_t sign = (i << 0) >> 31;
// Truncate mantissa
mantissa >>= 7;
// Re-bias exponent
exponent = exponent - 127 + 63;
if (exponent < 0) {
// Underflow: flush to zero
return sign << 23;
} else if (exponent > 0x7F) {
// Overflow: saturate to infinity
return (sign << 23) | (0x7F << 16);
}
return (sign << 23) | (exponent << 16) | mantissa;
}
void BasicHandler(const char *top, const char *message)
{
std::cout << top << std::endl << message << std::endl;
}
static void (*EHND)(const char *top, const char *message) = BasicHandler;
namespace Pica {
void InstallErrorCallback(void (*ErrorHandler)(const char *top,
const char *message)) {
EHND = ErrorHandler;
}
char *AssembleCode(const char *vertex, int &res_size) {
int rc = 0;
rc = AssembleString((char *)vertex, "llc_npi");
if (rc) {
EHND("Error when Assembling Code", vertex);
}
rc = RelocateProduct();
if (rc) {
EHND("Error when Relocating Product", "0");
}
FileClass f("Dont Care", "wb");
u32 progSize = g_outputBuf.size();
u32 dvlpSize = 10 * 4 + progSize * 4 + g_opdescCount * 8;
// Write DVLB header
f.WriteWord(0x424C5644); // DVLB
f.WriteWord(g_totalDvleCount); // Number of DVLEs
// Calculate and write DVLE offsets
u32 curOff = 2 * 4 + g_totalDvleCount * 4 + dvlpSize;
for (dvleTableIter dvle = g_dvleTable.begin(); dvle != g_dvleTable.end();
++dvle) {
if (dvle->nodvle)
continue;
f.WriteWord(curOff);
curOff += 16 * 4; // Header
curOff += dvle->constantCount * 20;
curOff += dvle->outputCount * 8;
curOff += dvle->uniformCount * 8;
curOff += dvle->symbolSize;
curOff = (curOff + 3) & ~3; // Word alignment
}
// Write DVLP header
f.WriteWord(0x504C5644); // DVLP
f.WriteWord(0); // version
f.WriteWord(10 * 4); // offset to shader binary blob
f.WriteWord(progSize); // size of shader binary blob
f.WriteWord(10 * 4 + progSize * 4); // offset to opdesc table
f.WriteWord(g_opdescCount); // number of opdescs
f.WriteWord(dvlpSize); // offset to symtable (TODO)
f.WriteWord(0); // ????
f.WriteWord(0); // ????
f.WriteWord(0); // ????
// Write program
for (outputBufIter it = g_outputBuf.begin(); it != g_outputBuf.end(); ++it)
f.WriteWord(*it);
// Write opdescs
for (int i = 0; i < g_opdescCount; i++)
f.WriteDword(g_opdescTable[i]);
// Write DVLEs
for (dvleTableIter dvle = g_dvleTable.begin(); dvle != g_dvleTable.end();
++dvle) {
if (dvle->nodvle)
continue;
curOff = 16 * 4;
f.WriteWord(0x454C5644); // DVLE
f.WriteHword(0x1002); // maybe version?
f.WriteByte(dvle->isGeoShader ? 1 : 0); // Shader type
f.WriteByte(dvle->isMerge ? 1 : 0);
f.WriteWord(dvle->entryStart); // offset to main
f.WriteWord(dvle->entryEnd); // offset to end of main
f.WriteHword(dvle->inputMask);
f.WriteHword(dvle->outputMask);
f.WriteByte(dvle->geoShaderType);
f.WriteByte(dvle->geoShaderFixedStart);
f.WriteByte(dvle->geoShaderVariableNum);
f.WriteByte(dvle->geoShaderFixedNum);
f.WriteWord(curOff); // offset to constant table
f.WriteWord(dvle->constantCount); // size of constant table
curOff += dvle->constantCount * 5 * 4;
f.WriteWord(curOff); // offset to label table (TODO)
f.WriteWord(0); // size of label table (TODO)
f.WriteWord(curOff); // offset to output table
f.WriteWord(dvle->outputCount); // size of output table
curOff += dvle->outputCount * 8;
f.WriteWord(curOff); // offset to uniform table
f.WriteWord(dvle->uniformCount); // size of uniform table
curOff += dvle->uniformCount * 8;
f.WriteWord(curOff); // offset to symbol table
f.WriteWord(dvle->symbolSize); // size of symbol table
// Sort uniforms by position
std::sort(dvle->uniformTable, dvle->uniformTable + dvle->uniformCount);
// Write constants
for (int i = 0; i < dvle->constantCount; i++) {
Constant &ct = dvle->constantTable[i];
f.WriteHword(ct.type);
if (ct.type == UTYPE_FVEC) {
f.WriteHword(ct.regId - 0x20);
for (int j = 0; j < 4; j++)
f.WriteWord(f32tof24(ct.fparam[j]));
} else if (ct.type == UTYPE_IVEC) {
f.WriteHword(ct.regId - 0x80);
for (int j = 0; j < 4; j++)
f.WriteByte(ct.iparam[j]);
} else if (ct.type == UTYPE_BOOL) {
f.WriteHword(ct.regId - 0x88);
f.WriteWord(ct.bparam ? 1 : 0);
}
if (ct.type != UTYPE_FVEC)
for (int j = 0; j < 3; j++)
f.WriteWord(0); // Padding
}
// Write outputs
for (int i = 0; i < dvle->outputCount; i++)
f.WriteDword(dvle->outputTable[i]);
// Write uniforms
size_t sp = 0;
for (int i = 0; i < dvle->uniformCount; i++) {
Uniform &u = dvle->uniformTable[i];
size_t l = u.name.length() + 1;
f.WriteWord(sp);
sp += l;
int pos = u.pos;
if (pos >= 0x20)
pos -= 0x10;
f.WriteHword(pos);
f.WriteHword(pos + u.size - 1);
}
// Write symbols
for (int i = 0; i < dvle->uniformCount; i++) {
std::string u(dvle->uniformTable[i].name);
std::replace(u.begin(), u.end(), '$', '.');
size_t l = u.length() + 1;
f.WriteRaw(u.c_str(), l);
}
// Word alignment
int pos = f.Tell();
int pad = ((pos + 3) & ~3) - pos;
for (int i = 0; i < pad; i++)
f.WriteByte(0);
}
res_size = f.Tell();
return (char *)f.get_ptr()->str().c_str();
}
} // namespace Pica

View File

@ -1,68 +0,0 @@
#pragma once
#include <stdint.h>
typedef uint64_t dword_t;
typedef uint32_t word_t;
typedef uint16_t hword_t;
typedef uint8_t byte_t;
typedef int64_t dlong_t;
typedef int32_t long_t;
typedef int16_t short_t;
typedef int8_t char_t;
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
#define BIT(n) (1U << (n))
#ifndef __BYTE_ORDER__
#include <sys/param.h>
#define __BYTE_ORDER__ BYTE_ORDER
#define __ORDER_LITTLE_ENDIAN__ LITTLE_ENDIAN
#define __ORDER_BIG_ENDIAN__ BIG_ENDIAN
#endif
#ifndef __llvm__
#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
static inline uint16_t __builtin_bswap16(uint16_t x)
{
return ((x << 8) & 0xff00) | ((x >> 8) & 0x00ff);
}
#if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
static inline uint32_t __builtin_bswap32(uint32_t x)
{
return ((x << 24) & 0xff000000) |
((x << 8) & 0x00ff0000) |
((x >> 8) & 0x0000ff00) |
((x >> 24) & 0x000000ff);
}
static inline uint64_t __builtin_bswap64(uint64_t x)
{
return (uint64_t)__builtin_bswap32(x>>32) |
((uint64_t)__builtin_bswap32(x&0xFFFFFFFF) << 32);
}
#endif
#endif
#endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define be_dword(a) __builtin_bswap64(a)
#define be_word(a) __builtin_bswap32(a)
#define be_hword(a) __builtin_bswap16(a)
#define le_dword(a) (a)
#define le_word(a) (a)
#define le_hword(a) (a)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define be_dword(a) (a)
#define be_word(a) (a)
#define be_hword(a) (a)
#define le_dword(a) __builtin_bswap64(a)
#define le_word(a) __builtin_bswap32(a)
#define le_hword(a) __builtin_bswap16(a)
#else
#error "What's the endianness of the platform you're targeting?"
#endif