summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorGrapheneCt2020-09-23 20:38:33 -0400
committerReiko Asakura2020-09-23 20:38:33 -0400
commitdcdbe6216e81cc5a32b4988c112a0520e5da6d61 (patch)
treeb66a2af223591ebbe9f50a7224b5aa436e0371db /include
parentAdd PowerVR service functions and errors (diff)
downloadvds-libraries-dcdbe6216e81cc5a32b4988c112a0520e5da6d61.tar.gz
Add gim.h
Diffstat (limited to 'include')
-rw-r--r--include/user/gim.h365
1 files changed, 365 insertions, 0 deletions
diff --git a/include/user/gim.h b/include/user/gim.h
new file mode 100644
index 0000000..2d83431
--- /dev/null
+++ b/include/user/gim.h
@@ -0,0 +1,365 @@
+#ifndef _DOLCESDK_PSP2_GIM_H_
+#define _DOLCESDK_PSP2_GIM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <psp2/gxm.h>
+#include <psp2/scebase.h>
+
+#include <psp2/kernel/clib.h>
+#include <psp2/kernel/sysmem.h>
+
+#define SCE_GIM_TAG 0x2E47494DUL /* 'GIM.' */
+#define SCE_GIM_VERSION 0x312E3030UL /* '1.00' */
+
+/** GIM data block types */
+#define SCE_GIM_BLOCK_TYPE_ROOT 0x02
+#define SCE_GIM_BLOCK_TYPE_PICTURE 0x03
+#define SCE_GIM_BLOCK_TYPE_IMAGE 0x04
+#define SCE_GIM_BLOCK_TYPE_PALETTE 0x05
+#define SCE_GIM_BLOCK_TYPE_FILEINFO 0xFF
+
+/** GIM texture data formats */
+#define SCE_GIM_TYPE_RGBA5650 0x0000
+#define SCE_GIM_TYPE_RGBA5551 0x0001
+#define SCE_GIM_TYPE_RGBA4444 0x0002
+#define SCE_GIM_TYPE_RGBA8888 0x0003
+#define SCE_GIM_TYPE_INDEX4 0x0004
+#define SCE_GIM_TYPE_INDEX8 0x0005
+
+/** GIM error codes */
+typedef int SceGimErrorCode;
+#define SCE_GIM_ERROR_INVALID_VALUE -1
+#define SCE_GIM_ERROR_INVALID_POINTER -2
+#define SCE_GIM_ERROR_INVALID_ALIGNMENT -3
+#define SCE_GIM_ERROR_NOT_FOUND -4
+
+#define SCE_GIM_PALETTE_SIZE_P4 64U
+#define SCE_GIM_PALETTE_SIZE_P8 1024U
+
+#define _SCE_GIM_ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
+
+/** A header for a GIM file.
+ This structure should be located right at the start of the GIM file.
+*/
+typedef struct SceGimHeader {
+ uint32_t tag; //!< GIM Identifier
+ uint32_t version; //!< Version number
+ uint32_t formatStyle; //!< GIM file format
+ uint32_t pad; //!< Padding
+} SceGimHeader;
+
+/* Contains information about data block in the GIM file. */
+typedef struct SceGimBlockInfo {
+ uint16_t blockId; //!< Block id (level)
+ uint16_t unk; //!< Always 0 on PSP2
+ uint32_t blockSize; //!< Size of this block + children blocks
+ uint32_t blockHeaderNext; //!< Offset to the next block header
+ uint32_t blockDataOffset; //!< Offset to the data of this block
+} SceGimBlockInfo;
+
+/* Contains information about texture block in the GIM file. */
+typedef struct SceGimTextureInfo {
+ uint16_t blockHeaderSize; //!< Size of this header (0x30)
+ uint16_t reference; //!< Always 0 on PSP2
+ uint16_t format; //!< Texture format
+ uint16_t pixelOrder; //!< Always 0 (normal order) on PSP2
+ uint16_t width; //!< Texture width
+ uint16_t height; //!< Texture height
+ uint16_t bppAlign; //!< Image/palette alignment BPP
+ uint16_t pitchAlign; //!< Image/palette alignment X
+ uint16_t heightAlign; //!< Image/palette alignment Y
+ uint16_t dimCount; //!< Always 2
+ uint16_t reserved; //!< Always 0
+ uint16_t reserved2; //!< Always 0
+ uint32_t indexStart; //!< Index relative start offset
+ uint32_t pixelsStart; //!< First plane/level/frame relative start offset
+ uint32_t pixelsEnd; //!< Last plane/level/frame relative end offset
+ uint32_t planeMask; //!< Always 0 on PSP2
+ uint16_t levelType;
+ uint16_t levelCount; //!< Number of mipmaps
+ uint16_t frameType; //!< Always 3
+ uint16_t frameCount; //!< Always 1 on PSP2 (static images)
+ uint32_t levelOffset; //!< Always 0x40 on PSP2
+ uint8_t pad[12]; //!< Padding
+} SceGimTextureInfo;
+
+#ifndef SCE_GIM_ERROR_RETURN
+#define SCE_GIM_ERROR_RETURN(COND, ERROR_CODE, FMT, ...) \
+ do { \
+ if (!(COND)) { return (ERROR_CODE); } \
+ } while (false)
+#endif
+
+#ifndef SCE_GIM_ASSERT
+#define SCE_GIM_ASSERT(x) ((void)(x))
+#endif
+
+/// Check if a value is aligned to the given power of 2 alignment.
+#define SCE_GIM_IS_ALIGNED(VALUE, ALIGNMENT) (((uint32_t)(VALUE) & ((ALIGNMENT) - 1)) == 0)
+
+/** Gets the header size of a GIM file.
+ @return The size of the header in bytes.
+*/
+inline uint32_t sceGimGetHeaderSize(void) {
+ return sizeof(SceGimHeader);
+}
+
+/** Gets the start address of the texture data within a GIM file.
+ @param gim A pointer to the GIM data.
+ @return A pointer to the start of the texture data.
+*/
+inline void* sceGimGetDataAddress(void *gim) {
+ return (void*)((uint32_t)gim + sceGimGetHeaderSize());
+}
+
+/** Gets the size of the texture data within a GIM file.
+ @param gim A pointer to the GIM data.
+ @return The size of the texture data in bytes.
+*/
+inline uint32_t sceGimGetDataSize(void *gim) {
+ void* data_hdr = sceGimGetDataAddress(gim);
+ SceGimBlockInfo *hdr = (SceGimBlockInfo*)data_hdr;
+ return hdr->blockSize;
+}
+
+/** Gets the size of the whole GIM file.
+ @param gim A pointer to the GIM data.
+ @return The size of the file in bytes.
+*/
+inline uint32_t sceGimGetSize(void *gim) {
+ return sceGimGetDataSize(gim) + sceGimGetHeaderSize();
+}
+
+/** Gets address of the image block.
+ @param gim A pointer to the GIM data.
+ @return A pointer to the start of the image block.
+*/
+inline void* sceGimFindImageAddress(void *gim) {
+
+ uint32_t nextHdrOffs = sceGimGetHeaderSize();
+ uint32_t gimSize = sceGimGetSize(gim);
+ SceGimBlockInfo *hdr;
+
+ while (nextHdrOffs < gimSize) {
+ hdr = (SceGimBlockInfo*)((uint32_t)gim + nextHdrOffs);
+
+ if (hdr->blockId == SCE_GIM_BLOCK_TYPE_IMAGE)
+ return (void *)hdr;
+
+ nextHdrOffs = hdr->blockHeaderNext + nextHdrOffs;
+ }
+
+ return NULL;
+}
+
+/** Gets address of the palette block.
+ @param gim A pointer to the GIM data.
+ @return A pointer to the start of the palette block.
+*/
+inline void* sceGimFindPaletteAddress(void *gim) {
+
+ uint32_t nextHdrOffs = sceGimGetHeaderSize();
+ uint32_t gimSize = sceGimGetSize(gim);
+ SceGimBlockInfo *hdr;
+
+ while (nextHdrOffs < gimSize) {
+ hdr = (SceGimBlockInfo*)((uint32_t)gim + nextHdrOffs);
+
+ if (hdr->blockId == SCE_GIM_BLOCK_TYPE_PALETTE)
+ return (void *)hdr;
+
+ nextHdrOffs = hdr->blockHeaderNext + nextHdrOffs;
+ }
+
+ return NULL;
+}
+
+/** Gets the number of textures in a GIM file.
+ @return The number of textures.
+*/
+inline uint32_t sceGimGetTextureCount(void *gim) {
+ return 1;
+}
+
+/** Initializes the texture control words for a given GIM texture.
+
+ @param texture A pointer to texture to be initialized.
+ @param gim A pointer to the GIM data.
+
+ @retval
+ SCE_OK The operation was successful.
+ @retval
+ SCE_GIM_ERROR_INVALID_ALIGNMENT The operation failed due to an invalid buffer alignment.
+ @retval
+ SCE_GIM_ERROR_INVALID_VALUE The operation failed due to an invalid input parameter.
+ @retval
+ SCE_GIM_ERROR_INVALID_POINTER The operation failed due to an invalid input pointer.
+*/
+inline SceGimErrorCode sceGimInitTexture(SceGxmTexture *texture, void *gim) {
+
+ SceGimTextureInfo *imgHdr = NULL;
+ SceGimHeader *hdr = (SceGimHeader*)gim;
+
+ // check parameters
+ SCE_GIM_ERROR_RETURN(
+ texture,
+ SCE_GIM_ERROR_INVALID_POINTER,
+ "");
+ SCE_GIM_ERROR_RETURN(
+ gim,
+ SCE_GIM_ERROR_INVALID_POINTER,
+ "");
+
+ void* img = sceGimFindImageAddress(gim);
+
+ SCE_GIM_ERROR_RETURN(
+ img,
+ SCE_GIM_ERROR_NOT_FOUND,
+ "");
+
+ void* pal = sceGimFindPaletteAddress(gim);
+
+ if (pal)
+ pal = (void*)((uint32_t)pal + 0x50);
+
+ imgHdr = (SceGimTextureInfo*)((uint32_t)img + 0x10);
+ img = (void*)((uint32_t)img + 0x50);
+
+ SceGxmTextureFormat texFormat;
+
+ if(hdr->version == SCE_GIM_VERSION) {
+ switch(imgHdr->format)
+ {
+ case SCE_GIM_TYPE_INDEX8:
+ texFormat = SCE_GXM_TEXTURE_FORMAT_P8_ABGR;
+ break;
+ case SCE_GIM_TYPE_INDEX4:
+ texFormat = SCE_GXM_TEXTURE_FORMAT_P4_ABGR;
+ break;
+ case SCE_GIM_TYPE_RGBA8888:
+ texFormat = SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_ABGR;
+ break;
+ case SCE_GIM_TYPE_RGBA4444:
+ texFormat = SCE_GXM_TEXTURE_FORMAT_U4U4U4U4_ABGR;
+ break;
+ case SCE_GIM_TYPE_RGBA5551:
+ texFormat = SCE_GXM_TEXTURE_FORMAT_U1U5U5U5_ABGR;
+ break;
+ case SCE_GIM_TYPE_RGBA5650:
+ texFormat = SCE_GXM_TEXTURE_FORMAT_U5U6U5_BGR;
+ break;
+ default:
+ // Unsupported type
+ SCE_GIM_ASSERT(0);
+ }
+ }
+ else {
+ SCE_GIM_ERROR_RETURN(
+ false,
+ SCE_GIM_ERROR_INVALID_VALUE,
+ "");
+ }
+
+ SceGxmErrorCode res = SCE_OK;
+
+ int32_t align = imgHdr->pitchAlign * 8 / imgHdr->bppAlign - 1;
+ int32_t strideWidth = (imgHdr->width + align) & ~align;
+
+ res = sceGxmTextureInitLinear(
+ texture,
+ img,
+ texFormat,
+ strideWidth,
+ imgHdr->height,
+ imgHdr->levelCount);
+
+ if (res < 0) {
+ return res;
+ }
+
+ if (pal) {
+ uint32_t pal_size = 0;
+
+ if (imgHdr->format == SCE_GIM_TYPE_INDEX8) {
+ pal_size = SCE_GIM_PALETTE_SIZE_P8;
+ }
+ else if (imgHdr->format == SCE_GIM_TYPE_INDEX4) {
+ pal_size = SCE_GIM_PALETTE_SIZE_P4;
+ }
+
+ pal_size = _SCE_GIM_ALIGN(pal_size, 4 * 1024);
+
+ SceUID id = sceKernelAllocMemBlock("gpu_mem", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, pal_size, NULL);
+
+ if (id < 0) {
+ return id;
+ }
+
+ void* pal_al;
+
+ sceKernelGetMemBlockBase(id, &pal_al);
+
+ res = sceGxmMapMemory(pal_al, pal_size, SCE_GXM_MEMORY_ATTRIB_READ);
+
+ if (res < 0) {
+ return res;
+ }
+
+ if (imgHdr->format == SCE_GIM_TYPE_INDEX8) {
+ sceClibMemcpy(pal_al, pal, SCE_GIM_PALETTE_SIZE_P8);
+ }
+ else if (imgHdr->format == SCE_GIM_TYPE_INDEX4) {
+ sceClibMemcpy(pal_al, pal, SCE_GIM_PALETTE_SIZE_P4);
+ }
+
+ res = sceGxmTextureSetPalette(texture, pal_al);
+ }
+
+ return res;
+}
+
+/** Checks if a pointer looks like a GIM file.
+
+ @param gim A pointer to the GIM data.
+
+ @retval
+ SCE_OK The data structure passes GIM header validation.
+ @retval
+ SCE_GIM_ERROR_INVALID_VALUE The operation failed because the header magic number was invalid
+ or the version numbers are not compatible.
+ @retval
+ SCE_GIM_ERROR_INVALID_POINTER The operation failed due to an invalid input pointer.
+*/
+inline SceGimErrorCode sceGimCheckData(void *gim) {
+ // check parameter
+ SCE_GIM_ERROR_RETURN(
+ gim,
+ SCE_GIM_ERROR_INVALID_POINTER,
+ "");
+
+ // check the magic sequence
+ SCE_GIM_ERROR_RETURN(
+ ((SceGimHeader*)gim)->tag == SCE_GIM_TAG,
+ SCE_GIM_ERROR_INVALID_VALUE,
+ "");
+
+ // check the header version
+ SCE_GIM_ERROR_RETURN(
+ ((SceGimHeader*)gim)->version == SCE_GIM_VERSION,
+ SCE_GIM_ERROR_INVALID_VALUE,
+ "");
+
+ // all ok
+ return SCE_OK;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DOLCESDK_PSP2_GIM_H_ */
+