/*---------------------------------------------------------------------------* Copyright 2010-2014 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ #ifndef _GX2UTINLINE_H_ #define _GX2UTINLINE_H_ #ifdef __cplusplus extern "C" { #endif /// @addtogroup GX2UTGX2RGroup /// @{ /// \brief Simple wrapper on a display list buffer that stores the used byte count typedef struct _GX2UTManagedDisplayList { GX2RBuffer displayList; u32 sizeUsed; } GX2UTManagedDisplayList; /// \brief Convert a GX2IndexFormat to a size in bytes /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE u32 GX2UTGetIndexSize(GX2IndexFormat format) { ASSERT(format==GX2_INDEX_FORMAT_U16 || format==GX2_INDEX_FORMAT_U32 || format==GX2_INDEX_FORMAT_U16_LE || format==GX2_INDEX_FORMAT_U32_LE); return (format==GX2_INDEX_FORMAT_U32 || format==GX2_INDEX_FORMAT_U32_LE) ? 4 : 2; } /// \brief Convert a size in bytes to a GX2IndexFormat /// \note Won't work with the _LE formats /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE GX2IndexFormat GX2UTGetIndexFormat(u32 size) { ASSERT(size==2 || size==4); return (size==4) ? GX2_INDEX_FORMAT_U32 : GX2_INDEX_FORMAT_U16; } /// \brief Get the size in bytes of a buffer /// \note The actual allocated size may be slightly larger due to end alignment /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE u32 GX2UTGetBufferSize(const GX2RBuffer* gx2Buffer) { return gx2Buffer->elementSize * gx2Buffer->elementCount; } /// \brief Zero out the given buffer struct /// \note GX2Buffers should be initialized to 0 before use, in particular the reserved fields must be zero. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2UTZeroBufferStruct(GX2RBuffer* gx2Buffer) { memset(gx2Buffer, 0, sizeof(GX2RBuffer)); } /// \brief Fill in a GX2Buffer struct /// \note This function will also ensure the reserved fields are zero. /// NOTE: no creation is done! /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2UTInitBufferStruct(GX2RBuffer* gx2Buffer, GX2RResourceFlags resourceFlags, u32 elementSize, u32 elementCount) { gx2Buffer->resourceFlags = resourceFlags; gx2Buffer->elementSize = elementSize; gx2Buffer->elementCount = elementCount; gx2Buffer->reserved[0]=0; } /// \brief Fill in a GX2Buffer struct and create the buffer. /// \note This function will also ensure the reserved fields are zero. /// /// \donotcall \gx2_typical \userheap \enddonotcall /// GX2_INLINE GX2Boolean GX2UTCreateBuffer(GX2RBuffer* gx2Buffer, GX2RResourceFlags resourceFlags, u32 elementSize, u32 elementCount) { gx2Buffer->resourceFlags = resourceFlags; gx2Buffer->elementSize = elementSize; gx2Buffer->elementCount = elementCount; gx2Buffer->reserved[0]=0; return GX2RCreateBuffer(gx2Buffer); } /// \brief Create a typical vertex buffer /// /// \donotcall \gx2_typical \userheap \enddonotcall /// GX2_INLINE GX2Boolean GX2UTCreateVertexBuffer(GX2RBuffer* gx2Buffer, u32 elementSize, u32 elementCount) { return GX2UTCreateBuffer(gx2Buffer, (GX2RResourceFlags)(GX2R_BIND_VERTEX_BUFFER | GX2R_USAGE_CPU_READWRITE | GX2R_USAGE_GPU_READ), elementSize, elementCount); } /// \brief Create a typical index buffer /// /// \donotcall \gx2_typical \userheap \enddonotcall /// GX2_INLINE GX2Boolean GX2UTCreateIndexBuffer(GX2RBuffer* gx2Buffer, u32 elementSize, u32 elementCount) { ASSERT(elementSize==2 || elementSize==4); return GX2UTCreateBuffer(gx2Buffer, (GX2RResourceFlags)(GX2R_BIND_INDEX_BUFFER | GX2R_USAGE_CPU_READWRITE | GX2R_USAGE_GPU_READ), elementSize, elementCount); } /// \brief Create a typical uniform block buffer /// /// \donotcall \gx2_typical \userheap \enddonotcall /// GX2_INLINE GX2Boolean GX2UTCreateUniformBlock(GX2RBuffer* gx2Buffer, u32 elementSize, u32 elementCount) { return GX2UTCreateBuffer(gx2Buffer, (GX2RResourceFlags)(GX2R_BIND_UNIFORM_BLOCK | GX2R_USAGE_CPU_READWRITE | GX2R_USAGE_GPU_READ), elementSize, elementCount); } /// \brief Create a typical shader buffer /// /// \donotcall \gx2_typical \userheap \enddonotcall /// GX2_INLINE GX2Boolean GX2UTCreateShaderProgram(GX2RBuffer* gx2Buffer, u32 programSize) { return GX2UTCreateBuffer(gx2Buffer, (GX2RResourceFlags)(GX2R_BIND_SHADER_PROGRAM | GX2R_USAGE_CPU_READWRITE | GX2R_USAGE_GPU_READ), programSize, 1); } /// \brief Create a typical display list buffer /// /// \donotcall \gx2_typical \userheap \enddonotcall /// GX2_INLINE GX2Boolean GX2UTCreateDisplayList(GX2RBuffer* gx2Buffer, u32 byteSize) { return GX2UTCreateBuffer(gx2Buffer, (GX2RResourceFlags)(GX2R_BIND_DISPLAY_LIST | GX2R_USAGE_CPU_READWRITE | GX2R_USAGE_GPU_READ), byteSize, 1); } /// \brief Create a "managed" display list that stores its current used size /// /// \donotcall \gx2_typical \userheap \enddonotcall /// GX2_INLINE GX2Boolean GX2UTCreateManagedDisplayList(GX2UTManagedDisplayList* managedDisplayList, u32 byteSize) { managedDisplayList->sizeUsed = 0; return GX2UTCreateDisplayList(&managedDisplayList->displayList, byteSize); } /// \brief Begin a managed display list /// /// \donotcall \gx2_dl \enddonotcall /// GX2_INLINE void GX2UTBeginManagedDisplayList(GX2UTManagedDisplayList* managedDisplayList) { managedDisplayList->sizeUsed = 0; GX2RBeginDisplayList(&managedDisplayList->displayList); } /// \brief End a managed display list /// /// \donotcall \gx2_typical \enddonotcall /// GX2_INLINE void GX2UTEndManagedDisplayList(GX2UTManagedDisplayList* managedDisplayList) { ASSERT(managedDisplayList->sizeUsed==0); // either not created or mismatched begin/end managedDisplayList->sizeUsed = GX2REndDisplayList(&managedDisplayList->displayList); } /// \brief Call a managed display list /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// GX2_INLINE void GX2UTCallManagedDisplayList(const GX2UTManagedDisplayList* managedDisplayList) { GX2RCallDisplayList(&managedDisplayList->displayList, managedDisplayList->sizeUsed); } /// \brief Direct call a managed display list /// /// \donotcall \nomulticore \gx2_dl \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// GX2_INLINE void GX2UTDirectCallManagedDisplayList(const GX2UTManagedDisplayList* managedDisplayList) { GX2RDirectCallDisplayList(&managedDisplayList->displayList, managedDisplayList->sizeUsed); } /// \brief Set an attribute buffer deriving the stride automatically from the buffer elementSize /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// GX2_INLINE void GX2UTSetAttributeBuffer(const GX2RBuffer* vertexBuffer, u32 slot, u32 byteOffset) { GX2RSetAttributeBuffer(vertexBuffer, slot, vertexBuffer->elementSize, byteOffset); } /// \brief Draw deriving the index format and index count automatically, with no offsets or instancing /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// GX2_INLINE void GX2UTDrawIndexed(GX2PrimitiveType primitiveType, const GX2RBuffer* indexBuffer) { GX2RDrawIndexed(primitiveType, indexBuffer, GX2UTGetIndexFormat(indexBuffer->elementSize), indexBuffer->elementCount, 0, 0, 1); } /// \brief Draw immediate deriving the index format and index count automatically, with no offsets or instancing /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// GX2_INLINE void GX2UTDrawIndexedImmediate(GX2PrimitiveType primitiveType, const GX2RBuffer* indexBuffer) { GX2RDrawIndexedImmediate(primitiveType, indexBuffer, GX2UTGetIndexFormat(indexBuffer->elementSize), indexBuffer->elementCount, 0, 0, 1); } /// \brief Create a geometry shader input ring buffer of the correct size for the given vertex shader /// /// \donotcall \gx2_typical \userheap \enddonotcall /// GX2_INLINE GX2Boolean GX2UTCreateGeometryShaderInputRingBuffer(GX2RBuffer* gx2Buffer, const GX2VertexShader *pVertexShader) { u32 byteCount= GX2CalcGeometryShaderInputRingBufferSize(pVertexShader->ringItemsize); return GX2UTCreateBuffer(gx2Buffer, (GX2RResourceFlags)(GX2R_BIND_GS_RING | GX2R_USAGE_GPU_READ | GX2R_USAGE_GPU_WRITE), byteCount, 1); } /// \brief Create a geometry shader output ring buffer of the correct size for the given geometry shader /// /// \donotcall \gx2_typical \userheap \enddonotcall /// GX2_INLINE GX2Boolean GX2UTCreateGeometryShaderOutputRingBuffer(GX2RBuffer* gx2Buffer, const GX2GeometryShader *pGeometryShader) { u32 byteCount= GX2CalcGeometryShaderOutputRingBufferSize(pGeometryShader->ringItemsize); return GX2UTCreateBuffer(gx2Buffer, (GX2RResourceFlags)(GX2R_BIND_GS_RING | GX2R_USAGE_GPU_READ | GX2R_USAGE_GPU_WRITE), byteCount, 1); } /// \brief Set the geometry shader input and output buffers /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// GX2_INLINE void GX2UTSetGeometryShaderRingBuffers(const GX2RBuffer* ringInBuffer, const GX2RBuffer* ringOutBuffer) { GX2RSetGeometryShaderInputRingBuffer(ringInBuffer); GX2RSetGeometryShaderOutputRingBuffer(ringOutBuffer); } /// \brief Initialize the fetch shader assuming no tesselation /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2UTInitFetchShader(GX2FetchShader* fetchShader, GX2RBuffer* shaderProgram, u32 attribCount, const GX2AttribStream* attribStreams) { GX2RInitFetchShader(fetchShader, shaderProgram, attribCount, attribStreams, GX2_FETCH_SHADER_TESSELATION_NONE, GX2_TESSELLATION_MODE_DISCRETE); } /// \brief Lock the buffer, copy byteCount bytes from pSrc into it, and unlock /// /// \donotcall \fgonly \notthreadsafe \notinterrupt \notexception \devonly \enddonotcall /// GX2_INLINE void GX2UTFillBufferEx(GX2RBuffer* gx2Buffer, void *pSrc, u32 byteCount) { void *pMem=GX2RLockBuffer(gx2Buffer); memcpy(pMem, pSrc, byteCount); GX2RUnlockBuffer(gx2Buffer); } /// \brief Lock the buffer, copy bytes from pSrc into it (size of entire buffer), and unlock. /// /// \donotcall \fgonly \notthreadsafe \notinterrupt \notexception \devonly \enddonotcall /// GX2_INLINE void GX2UTFillBuffer(GX2RBuffer* gx2Buffer, void *pSrc) { GX2UTFillBufferEx(gx2Buffer, pSrc, GX2UTGetBufferSize(gx2Buffer)); } /// \brief Call \ref GX2RInvalidateBuffer() with GX2R_OPTION_NONE /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \writesgpu{if the buffer may be read or written by GPU.} /// GX2_INLINE void GX2UTInvalidateBuffer(const GX2RBuffer* gx2Buffer) { GX2RInvalidateBuffer(gx2Buffer, GX2R_OPTION_NONE); } /// \brief Macro to name a buffer by its variable name #define GX2UTSetBufferVarName(x) GX2RSetBufferName(&x, #x) /// \brief Lock/Unlock the buffer and endian swap the contents /// /// \donotcall \fgonly \notthreadsafe \notinterrupt \notexception \devonly \enddonotcall /// GX2_INLINE void GX2UTEndianSwapBuffer(GX2RBuffer* gx2Buffer) { void *pMem=GX2RLockBuffer(gx2Buffer); GX2EndianSwap(pMem, GX2UTGetBufferSize(gx2Buffer)); GX2RUnlockBuffer(gx2Buffer); } /// \brief Lock/Unlock the buffer and endian swap the contents, pass options to \ref GX2RUnlockBufferEx /// /// \donotcall \fgonly \notthreadsafe \notinterrupt \notexception \devonly \enddonotcall /// GX2_INLINE void GX2UTEndianSwapBufferEx(GX2RBuffer* gx2Buffer, GX2RResourceFlags optionFlags) { void *pMem=GX2RLockBuffer(gx2Buffer); GX2EndianSwap(pMem, GX2UTGetBufferSize(gx2Buffer)); GX2RUnlockBufferEx(gx2Buffer, optionFlags); } /// \brief Set up all the user fields of a GX2Surface. /// \note This function does not call \ref GX2CalcSurfaceSizeAndAlignment /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2UTInitSurfaceStruct(GX2Surface *gx2Surface, GX2RResourceFlags resourceFlags, u32 width, u32 height, u32 depth, u32 numMips, GX2SurfaceDim dim, GX2SurfaceFormat format, GX2AAMode aa) { GX2_CHECK_ENUM_RANGE(dim, GX2_SURFACE_DIM) GX2_CHECK_ENUM_RANGE(format, GX2_SURFACE_FORMAT) GX2_CHECK_ENUM_RANGE(aa, GX2_AA_MODE) gx2Surface->dim = dim; gx2Surface->width = width; gx2Surface->height = height; gx2Surface->depth = depth; gx2Surface->numMips = numMips; gx2Surface->format = format; gx2Surface->aa = aa; gx2Surface->resourceFlags = resourceFlags; gx2Surface->tileMode = GX2_TILE_MODE_DEFAULT; gx2Surface->swizzle = 0; gx2Surface->imagePtr = NULL; gx2Surface->mipPtr = NULL; } /// \brief Set the color buffers and depth buffer for rendering. /// /// This function sets the color buffers and depth buffers for rendering. It /// is valid to pass 0 as the number of color buffers for depth only rendering. /// It is valid to pass NULL as the depth buffer. /// /// \note The AA mode will be set to the value found in the first GX2ColorBuffer /// or, if there are no color buffers, the value in the GX2DepthBuffer. /// /// \note Functions \ref GX2SetColorBuffer() and \ref GX2SetDepthBuffer() can be /// used to individually set color buffers and the depth buffer. /// /// \param numColorBuffers Number of color buffers, starting at GX2_RENDER_TARGET_0. /// \param colorBuffers Pointer to an array of GX2ColorBuffer pointers. /// \param depthBuffer Pointer to a GX2DepthBuffer, may be NULL. /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// GX2_INLINE void GX2UTSetRenderTargets(u32 numColorBuffers, const GX2ColorBuffer **colorBuffers, const GX2DepthBuffer *depthBuffer) { if(numColorBuffers != 0) { u32 i; ASSERT(numColorBuffers <= (u32)GX2_RENDER_TARGET_LAST + 1); ASSERT(colorBuffers); for(i = 0; i < numColorBuffers; i++) { ASSERT(colorBuffers[i]); GX2SetColorBuffer(colorBuffers[i], (GX2RenderTarget)i); } } if(depthBuffer != NULL) { GX2SetDepthBuffer(depthBuffer); if(numColorBuffers == 0) { GX2SetAAMode(depthBuffer->surface.aa); } } } /// @} /// @addtogroup GX2UTCaptureGroup /// @{ /// \brief Thin wrapper on GX2DebugTagUserString(GX2_DEBUG_TAG_INDENT) /// /// \donotcall \fgonly \notthreadsafe \notinterrupt \notexception \devonly \enddonotcall /// GX2_INLINE void GX2UTDebugTagIndent( const char* formatString, ... ) { va_list args; va_start(args, formatString); GX2DebugTagUserStringVA(GX2_DEBUG_TAG_INDENT, formatString, args); va_end(args); } /// \brief Thin wrapper on GX2DebugTagUserString(GX2_DEBUG_TAG_UNDENT) /// /// \donotcall \fgonly \notthreadsafe \notinterrupt \notexception \devonly \enddonotcall /// GX2_INLINE void GX2UTDebugTagUndent(void) { GX2DebugTagUserString(GX2_DEBUG_TAG_UNDENT, NULL); } /// \brief Thin wrapper on GX2DebugTagUserString(GX2_DEBUG_TAG_COMMENT) /// /// \donotcall \fgonly \notthreadsafe \notinterrupt \notexception \devonly \enddonotcall /// GX2_INLINE void GX2UTDebugTagComment( const char* formatString, ... ) { va_list args; va_start(args, formatString); GX2DebugTagUserStringVA(GX2_DEBUG_TAG_COMMENT, formatString, args); va_end(args); } /// \brief Thin wrapper on GX2DebugTagUserString(GX2_DEBUG_TAG_BOOKMARK) /// /// \donotcall \fgonly \notthreadsafe \notinterrupt \notexception \devonly \enddonotcall /// GX2_INLINE void GX2UTDebugTagBookmark( const char* formatString, ... ) { va_list args; va_start(args, formatString); GX2DebugTagUserStringVA(GX2_DEBUG_TAG_BOOKMARK, formatString, args); va_end(args); } /// \brief Convenience function for rounding a u32 to the nearest power of 2. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE u32 GX2UTRoundNearestPow2(u32 value) { // Special bit-twiddle that rounds up to nearest power of 2. value--; value |= value >> 1; value |= value >> 2; value |= value >> 4; value |= value >> 8; value |= value >> 16; value++; return value; } /// @} #ifdef __cplusplus } #endif // __cplusplus #endif // _GX2UTINLINE_H_