Compare commits

..

6 Commits

Author SHA1 Message Date
98c8639bd5
Merge branch 'devkitPro:master' into master 2024-10-12 18:29:36 +02:00
oreo639
d522455ea5 Print warning when attempting to use swizzling in outmask 2023-10-11 21:32:43 +02:00
4019766d8d Update for better comp 2022-12-25 11:30:26 +01:00
6a6c3ed1cf Fix a Big Mistake 2022-12-25 02:56:46 +01:00
=
b614217a82 File Support 2022-12-23 05:05:50 +01:00
=
6c76004761 DONT USE THIS LIBRARY IF YOU DON'T KNOW HOW TO USE 2022-12-23 04:59:41 +01:00
17 changed files with 947 additions and 24 deletions

1
.gitignore vendored
View File

@ -26,6 +26,5 @@ missing
config.log
config.status
Makefile
picasso
.deps/
*.bz2

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)
#########################################################################################

57
CMakeLists.txt Normal file
View File

@ -0,0 +1,57 @@
cmake_minimum_required(VERSION 3.22)
project(picasso VERSION 0.5.2 LANGUAGES CXX DESCRIPTION "Picasso Shadercompiler on the Nintendo 3ds")
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__")
include(CMakePackageConfigHelpers)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING
"Choose the type of build, options are: None Debug Release."
FORCE)
endif(NOT CMAKE_BUILD_TYPE)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE STRING
"The install location"
FORCE)
endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
include_directories(include)
set(HEADER_FILES
include/pica.hpp
include/picasso/picasso.h
include/picasso/types.h
include/picasso/FileClass.h
include/picasso/maestro_opcodes.h)
set(SOURCE_FILES
source/picasso_assembler.cpp
source/picasso_library.cpp)
add_library(${PROJECT_NAME}
${HEADER_FILES}
${SOURCE_FILES})
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_compile_features(${PROJECT_NAME}
# Features required to compile the library itself.
PRIVATE cxx_std_20 cxx_auto_type)
set(PROJECT_PREFIX ${PROJECT_NAME}-${picasso_VERSION})
target_include_directories(${PROJECT_NAME}
PUBLIC
# Used when building the library:
$<BUILD_INTERFACE:${foo_SOURCE_DIR}/include>
# Used when installing the library:
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>
PRIVATE
# Used only when building the library:
src)

View File

@ -0,0 +1,14 @@
@PACKAGE_INIT@
# Include the exported CMake file
get_filename_component(picasso_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
# This macro enables usage of find_dependency().
# https://cmake.org/cmake/help/v3.11/module/CMakeFindDependencyMacro.html
include(CMakeFindDependencyMacro)
if(NOT TARGET picasso::picasso)
include("${picasso_CMAKE_DIR}/picasso-targets.cmake")
endif()
check_required_components(picasso)

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:

42
example/CMakeLists.txt Normal file
View File

@ -0,0 +1,42 @@
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 "/opt/devkitpro/libctru/default_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)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.smdh
COMMAND smdhtool --create "${APP_TITLE}" "${APP_DESCRIPTION}" "${APP_AUTHOR}" "${APP_ICON}" ${PROJECT_NAME}.smdh
DEPENDS ${PROJECT_NAME}.elf
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.3dsx
COMMAND 3dsxtool ${PROJECT_NAME}.elf ${PROJECT_NAME}.3dsx --romfs=${APP_ROMFS} --smdh=${PROJECT_NAME}.smdh
DEPENDS ${PROJECT_NAME}.elf
)
add_custom_target( 3ds ALL
DEPENDS ${PROJECT_NAME}.smdh ${PROJECT_NAME}.3dsx
)

View File

@ -0,0 +1,36 @@
; 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

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

@ -0,0 +1,174 @@
#include <3ds.h>
#include <citro3d.h>
#include <pica.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();
romfsInit();
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
//vshader_shbin = Pica::AssembleCode(vertShader, vshader_shbin_size);
vshader_shbin = Pica::AssembleFile("romfs:/vshader.pica", 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;
}

10
include/pica.hpp Normal file
View File

@ -0,0 +1,10 @@
#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);
char* AssembleFile(const char* file, int &res_size);
}

View File

@ -1,43 +1,44 @@
#pragma once
#include <stdio.h>
#include "types.h"
#include "picasso/types.h"
#include <sstream>
#include <string>
class FileClass
{
FILE* f;
std::stringstream 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;
f.read((char*)buffer, size);
filePos += size;
return size;
}
size_t _RawWrite(const void* buffer, size_t size)
{
size_t x = fwrite(buffer, 1, size, f);
filePos += x;
return x;
f.write((const char*)buffer, size);
filePos += size;
return size;
}
public:
FileClass(const char* file, const char* mode) : LittleEndian(true), own(true), filePos(0)
{
f = fopen(file, mode);
//Do nothing
}
FileClass(FILE* inf) : f(inf), LittleEndian(true), own(false), filePos(0) { }
~FileClass()
{
if (f && own) fclose(f);
//Do nothing
}
void SetLittleEndian() { LittleEndian = true; }
void SetBigEndian() { LittleEndian = false; }
FILE* get_ptr() { return f; }
bool openerror() { return f == NULL; }
std::stringstream* get_ptr() { return &f; }
bool openerror() { return false; }
dword_t ReadDword()
{
@ -103,13 +104,11 @@ public:
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)
@ -129,4 +128,4 @@ static inline char* StringFromFile(const char* filename)
buf[size] = 0;
fclose(f);
return buf;
}
}

View File

@ -54,4 +54,4 @@ enum
// Only the upper 3 bits are used for the following opcodes
MAESTRO_MADI = 0x30,
MAESTRO_MAD = 0x38,
};
};

View File

@ -16,9 +16,9 @@
#include <string>
#include <algorithm>
#include "FileClass.h"
#include "picasso/FileClass.h"
#include "maestro_opcodes.h"
#include "picasso/maestro_opcodes.h"
#if !defined(WIN32) && !defined(stricmp)
#define stricmp strcasecmp
@ -253,4 +253,4 @@ struct DVLEData
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

@ -65,4 +65,4 @@ static inline uint64_t __builtin_bswap64(uint64_t x)
#define le_hword(a) __builtin_bswap16(a)
#else
#error "What's the endianness of the platform you're targeting?"
#endif
#endif

View File

@ -1,4 +1,4 @@
#include "picasso.h"
#include "picasso/picasso.h"
//#define DEBUG
#define BUF g_outputBuf
@ -548,9 +548,13 @@ static int maskFromSwizzling(int sw, bool reverse = true)
{
sw >>= 1; // get rid of negation bit
int out = 0;
int prevbitid = 4;
for (int i = 0; i < 4; i ++)
{
int bitid = (sw>>(i*2))&3;
if (bitid > prevbitid)
fprintf(stderr, "%s:%d: warning: arbitrary swizzling has no effect for destination mask\n", curFile, curLine);
prevbitid=bitid;
if (reverse) bitid = 3 - bitid;
out |= BIT(bitid);
}

199
source/picasso_library.cpp Normal file
View File

@ -0,0 +1,199 @@
#include <pica.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();
}
char *AssembleFile(const char *file, int &res_size) {
char *sourceCode = StringFromFile(file);
if (!sourceCode) {
EHND("error:", "cannot open input file!\n");
}
return AssembleCode(sourceCode, res_size);
}
} // namespace Pica