/*---------------------------------------------------------------------------* Copyright (C) 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. *---------------------------------------------------------------------------*/ // ------------------------------------------------------- // gx2Surface.h (Shared between PC:gtxConvert and Gx2) // // Declares surface-related types & functions for gx2 library. // // Note. Data structures in this file exist in serialized // format in .gtx texture files. Modifying any of the structures // hence runs huge risk of invalidating any or all texture files. // // Also - do not add non 32-bit/element fields into these data structures, // they may not serialize correctly. // ------------------------------------------------------- #ifndef _CAFE_GX2_SURFACE_H_ #define _CAFE_GX2_SURFACE_H_ #include #ifdef __cplusplus extern "C" { #endif /// @addtogroup GX2SurfaceGroup /// @{ /// @addtogroup GX2SurfaceAllGroup /// @{ //---------------------------------------------------------------------- // Defines /// \brief The number of registers used to describe textures #define GX2_NUM_TEXTURE_REGISTERS 5 /// \brief The number of registers used to describe color buffers /// #define GX2_NUM_COLOR_BUFFER_REGISTERS 5 /// \brief The number of registers used to describe depth/stencil buffers /// #define GX2_NUM_DEPTH_BUFFER_REGISTERS 7 /// \brief The number of registers used to describe HiStencil pretest state /// #define GX2_NUM_HISTENCIL_STATES 2 /// \brief Minimum offset from pixel center of MSAA buffer. It ranges -8/16 to 7/16. /// #define GX2_MSAA_SAMPLE_LOCATION_MIN -8 /// \brief Maximum offset from pixel center at MSAA buffer. It ranges -8/16 to 7/16. /// #define GX2_MSAA_SAMPLE_LOCATION_MAX 7 //---------------------------------------------------------------------- // Structures // !!!Note!!! - The GX2Surface structure is burned into .gtx file. // Altering parameters or changing their order may invalidate all existing content. /// \brief Describes a "surface", the common base element of textures, color & depth buffers. /// /// Since surfaces are very complex, all the user parameters are encapsulated in this structure. /// In addition, there are fields for some computed values that are useful both for the user /// as well as for certain APIs. They are stored here to avoid calculating them multiple times. /// Whenever a user value is changed, it's a good idea to call GX2CalcSurfaceSizeAndAlignment. /// #ifdef __ghs__ #pragma ghs nowarning 619 // "nonstandard unnamed field" for anonymous union when compiled as C #endif typedef struct _GX2Surface { // Caution: This structure is serialized in the .gtx file format. // Don't add non 32-bit per element sized fields; they may not transfer correctly. /// (user) dimension: 1D, 2D, 3D, etc. GX2SurfaceDim dim; /// (user) size of s (x) dimension in pixels u32 width; /// (user) size of t (y) dimension in pixels u32 height; /// (user) size of r (p, z) dimension in pixels. 0 implies 1. u32 depth; /// (user) number of mip levels, counting base level 0 as 1. 0 implies 1. u32 numMips; /// (user) image format GX2SurfaceFormat format; /// (user) antialiasing mode GX2AAMode aa; union { /// (user) intended use (texture, color buffer, etc) (if not using GX2R) GX2SurfaceUse use; /// (user) type, semantics and options, if using GX2R GX2RResourceFlags resourceFlags; }; /// (calc) size of texture base image (level 0), in bytes u32 imageSize; union { /// (user) pointer to texture base image (level 0) void *imagePtr; void *pMem; }; /// (calc) size of mipmap pyramid (levels 1+), in bytes. May be 0. u32 mipSize; /// (user) pointer to mipmap pyramid (levels 1+). May be NULL. void *mipPtr; /// (special) base tiling mode for the texture GX2TileMode tileMode; /// (special) pipe and bank swizzle modes for optimizing memory access /// The lower 8 bits are 0 and unused. The next 8 bits are the swizzle value, of which only /// values 0 through 7 are valid (set using GX2SetSurfaceSwizzle). The next 8 bits are /// the mip-level at which the hardware stops swizzling and switches to using 1D tiling modes (calculated; not set by the user). u32 swizzle; /// (calc) alignment to use when allocating image and mip levels, in bytes u32 alignment; /// (calc) used internally to set registers; padded image width in elements (pixels or BC 4x4 tiles) u32 pitch; /// \brief (calc) Offsets to each mip level, in bytes. /// /// mipOffset[0] is special: it can be used to place levels 1+ after the base map. /// (It indicates the size of the base map plus the padding needed for level 1.) /// It should not be used for any other purpose. /// /// The location of a mip level image should be found only as follows: /// - level 0 is given by imagePtr /// - level 1 is given by mipPtr /// - levels 2+ are given by (u32) mipPtr + mipOffset[level-1] /// /// \note This array is computed to reflect what the mipmapping hardware does intrinsically. /// Altering it will not change the hardware's behavior. /// It is provided to help software find the mip data when needed. /// u32 mipOffset[ 13 ]; // TODO: use GX2_LOG2_MAX_TEXTURE_SIZE instead } GX2Surface; #ifdef __ghs__ #pragma ghs endnowarning #endif /// @} /// @addtogroup GX2SurfaceColorGroup /// @{ /// \brief Completely describes a color buffer (i.e., render target). /// /// In addition to GX2Surface, includes user fields to describe a color buffer. /// Also includes hardware register settings for the same purpose. /// It allows rendering to a given mip level or array slice. /// typedef struct _GX2ColorBuffer { /// main surface description GX2Surface surface; /// (user) mip level to use (usually 0) u32 viewMip; /// (user) start slice in the array or 3D surface (usually 0) u32 viewFirstSlice; /// (user) number of slices (usually 1) u32 viewNumSlices; /// Auxiliary buffer (for AA only) address void *auxPtr; /// Auxiliary buffer (for AA only) size u32 auxSize; /// (calc) private, calculated by driver u32 _regs[GX2_NUM_COLOR_BUFFER_REGISTERS]; } GX2ColorBuffer; /// @} /// @addtogroup GX2SurfaceDepthGroup /// @{ /// \brief Completely describes a depth/stencil buffer. /// /// In addition to GX2Surface, includes user fields to describe a depth/stencil buffer. /// Also includes hardware register settings for the same purpose. /// It allows rendering to a given mip level or array slice. /// typedef struct _GX2DepthBuffer { /// main surface description GX2Surface surface; /// (user) mip level to use (usually 0) u32 viewMip; /// (user) start slice in the array or 3D surface (usually 0) u32 viewFirstSlice; /// (user) number of slices (usually 1) u32 viewNumSlices; /// Hierarchical Z buffer address (optional) void *hiZPtr; /// Hierarchical Z buffer size (optional) u32 hiZSize; /// (user) Value to use when clearing the depth buffer f32 clearDepth; /// (user) Value to use when clearing the stencil buffer. Only the least significant 8 bits are valid. u32 clearStencil; /// (calc) private, calculated by driver u32 _regs[GX2_NUM_DEPTH_BUFFER_REGISTERS]; } GX2DepthBuffer; /// \brief Describes a single HiStencil pretest state. /// /// Supplied to \ref GX2HiStencilInfo to completely describe HiStencil pretest state /// typedef struct _GX2HiStencilState { /// (user) compare function GX2CompareFunction function; /// (user) reference value u8 reference; /// (user) mask u8 mask; /// (user) enable GX2Boolean enable; } GX2HiStencilState; /// \brief Describes all HiStencil pretest states. /// /// Must be used in conjunction w/ GX2DepthBuffer to completely describe depth/stencil buffer /// typedef struct _GX2HiStencilInfo { /// (user) compare function GX2HiStencilState state[GX2_NUM_HISTENCIL_STATES]; /// (calc) private, calculated by driver u32 _regs[GX2_NUM_HISTENCIL_STATES]; } GX2HiStencilInfo; /// @} /// @addtogroup GX2SurfaceAllGroup /// @{ // Rectangular region // left, top are inclusive. // right, bottom are exclusive // 0,0 is the upper left of the surface typedef struct _GX2RectInt { s32 left; s32 top; s32 right; s32 bottom; } GX2RectInt; // A point // 0,0 is the upper left of the surface typedef struct _GX2PointInt { s32 x; s32 y; } GX2PointInt; // An AA sampling point // 0,0 is center of the AA sampling point // It ranges -8 to 7 offset from pixel center. typedef struct _GX2AASampleLoc { s8 x[8]; s8 y[8]; } GX2AASampleLoc; /// @} /// @addtogroup GX2SurfaceAllGroup /// @{ //---------------------------------------------------------------------- // Functions /// \brief Given a surface structure with user fields set, fill in size & other computed values. /// /// \note There is presently a bug in this function concerning the selection of tile mode /// to use for BCx compressed textures below a certain size (128x64 pixels). If given /// GX2_TILE_MODE_DEFAULT, the function will choose GX2_TILE_MODE_2D_TILED_THIN1. /// However, it should choose GX2_TILE_MODE_1D_TILED_THIN1 for BCx textures below the /// size of 128x64 pixels. This affects the main image (mip 0) calculation. The /// function will correctly recognize that the smaller mip levels are all 1D tiled. /// This function will be fixed in a future SDK; you should work around it in the mean /// time by avoiding the use of GX2_TILE_MODE_DEFAULT for BCx textures below 128x64 /// pixels (use GX2_TILE_MODE_1D_TILED_THIN1 instead). /// /// \param surface Ptr to surface structure to update /// /// \donotcall \threadsafe \devonly \enddonotcall /// void GX2API GX2CalcSurfaceSizeAndAlignment(GX2Surface *surface); /// @} /// @addtogroup GX2SurfaceColorGroup /// @{ /// \brief Given an initialized color buffer, calculate the size and alignment /// for the aux (AA) buffer. AA surfaces must have an aux buffer set up. /// /// \param colorBuffer Ptr to initialized colorBuffer structure to inquire about /// \param pSize Ptr to u32 to hold calculated size /// \param pAlign Ptr to u32 to hold calculated alignment /// /// \donotcall \threadsafe \devonly \enddonotcall /// void GX2API GX2CalcColorBufferAuxInfo(GX2ColorBuffer *colorBuffer, u32 *pSize, u32 *pAlign); /// \brief Given a color buffer structure with user fields set, fill in register values. /// /// \param colorBuffer Ptr to color buffer structure to update. /// /// \donotcall \threadsafe \devonly \enddonotcall /// void GX2API GX2InitColorBufferRegs(GX2ColorBuffer *colorBuffer); /// @} /// @addtogroup GX2SurfaceDepthGroup /// @{ /// \brief Given an initialized depth buffer, calculate the size and alignment /// for the Hi-Z buffer. The Hi-Z buffer is optional; it improves performance. /// /// \param depthBuffer Ptr to initialized depthBuffer structure to inquire about /// \param pSize Ptr to u32 to hold calculated size /// \param pAlign Ptr to u32 to hold calculated alignment /// /// \donotcall \threadsafe \devonly \enddonotcall /// void GX2API GX2CalcDepthBufferHiZInfo(GX2DepthBuffer *depthBuffer, u32 *pSize, u32 *pAlign); /// \brief Given a depth buffer structure with user fields set, fill in register values. /// /// \param depthBuffer Ptr to depth buffer structure to update. /// /// \donotcall \threadsafe \devonly \enddonotcall /// void GX2API GX2InitDepthBufferRegs(GX2DepthBuffer *depthBuffer); /// \brief Allows setting the Hi-Z enable bit within a depth buffer structure /// /// \note The Hi-Z buffer ptr must be set (\ref GX2InitDepthBufferHiZPtr) /// before enabling Hi-Z /// /// \param depthBuffer Ptr to depth buffer structure to update. /// \param hiZEnable boolean indicating whether hiZ should be enabled. /// /// \donotcall \threadsafe \devonly \enddonotcall /// void GX2API GX2InitDepthBufferHiZEnable(GX2DepthBuffer *depthBuffer, GX2Boolean hiZEnable); /// \brief Allows setting the Z Range Base within a depth buffer structure. /// /// This function sets the Z Range Base setting for HiZ testing. The default /// state is \ref GX2_ZRANGE_BASE_ZMIN (ideal for \ref GX2_COMPARE_GREATER and /// \ref GX2_COMPARE_GEQUAL). Otherwise, \ref GX2_ZRANGE_BASE_ZMAX should be /// used. /// /// \note This routine should be executed after \ref GX2InitDepthBufferRegs. /// Calling GX2InitDepthBufferRegs will reset this back to /// \ref GX2_ZRANGE_BASE_ZMIN. /// /// \warning The depth buffer must be clear or about to be cleared when the Z /// Range Base is changed or depth buffer corruption may result. /// /// \param depthBuffer Ptr to depth buffer structure to update. /// \param rangeBase enum indicating which Z Range Base to use. /// /// \donotcall \threadsafe \devonly \enddonotcall /// void GX2API GX2InitDepthBufferRangeBase(GX2DepthBuffer *depthBuffer, GX2ZRangeBase rangeBase); /// \brief Given a HiStencilInfo structure with user fields set, fill in register values. /// /// \param hiStencilInfo A set of 2 HiStencil pretest states. /// void GX2API GX2InitHiStencilInfoRegs(GX2HiStencilInfo *hiStencilInfo); /// \brief Helper function to set up HiStencilInfo structure in a convenient way. /// /// \param hiStencilInfo Ptr to HiStencil info structure to update. /// \param state0 A HiStencil pretest state /// \param state1 A HiStencil pretest state /// GX2_INLINE void GX2InitHiStencilInfo(GX2HiStencilInfo *hiStencilInfo, GX2HiStencilState *state0, GX2HiStencilState *state1) { ASSERT(hiStencilInfo); if (state0) hiStencilInfo->state[0] = *state0; if (state1) hiStencilInfo->state[1] = *state1; GX2InitHiStencilInfoRegs(hiStencilInfo); } /// @} /// @addtogroup GX2SurfaceColorGroup /// @{ /// \brief Sets the given color buffer to be used as the given render target. /// /// The 'use' field must indicate color buffer usage. /// /// \note These set functions always update the address register based upon /// the user-provided pointer (thus there is no need to call the init /// function again when only changing the address pointer). /// /// \note The AA value within the given colorBuffer will only be set to the hardware /// when the target parameter is 0 (or GX2_RENDER_TARGET_0). The AA values for the /// depth buffer and all color buffers which are in use must match. GX2 currently /// does not verify this requirement. See Also \ref GX2SetAAMode(). /// /// \note Warning: This function does not set the scissor box to the size of the color /// buffer. To prevent writing outside of the color buffer, \ref GX2SetScissor should be /// called in conjunction this function. /// /// \param colorBuffer Ptr to color buffer structure to use; all fields & registers should already be initialized. /// \param target Which render target to configure /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// void GX2API GX2SetColorBuffer(const GX2ColorBuffer *colorBuffer, GX2RenderTarget target); /// @} /// @addtogroup GX2SurfaceDepthGroup /// @{ /// \brief Sets the given depth buffer to be used as the depth/stencil target. /// /// The 'use' field must indicate depth buffer usage. /// /// \note These set functions always update the address register based upon /// the user-provided pointer (thus there is no need to call the init /// function again when only changing the address pointer). /// /// \note Warning: This function doesn't set the AA registers. When setting just a depth /// buffer, verify that the AA mode of this depth buffer matches that of the last /// color buffer that was set, or call /ref GX2SetAAMode() if you need to explicitly /// set the AA mode for the depth buffer. /// /// \warning This function does not set the scissor box to the size of the color /// buffer. To prevent writing outside of the color buffer, \ref GX2SetScissor should be /// called in conjunction this function. /// /// \param depthBuffer Ptr to depth buffer structure to use; all fields & registers should already be initialized. /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// void GX2API GX2SetDepthBuffer(const GX2DepthBuffer *depthBuffer); /// \brief Sets the given HiStencil info to be used as the HiStencil pretest state. /// /// Must be used in conjunction with \ref GX2SetDepthBuffer in order to fully /// describe the depth/stencil buffer when HiStencil is used. /// /// \param hiStencilInfo Ptr to HiStencil info structure to use; all fields & registers should already be initialized. /// void GX2API GX2SetHiStencilInfo(const GX2HiStencilInfo *hiStencilInfo); /// @} /// @addtogroup GX2SurfaceColorGroup /// @{ /// \brief Helper function for initializing color buffers /// /// \warning Do not use this function. Instead use /// \ref GX2InitColorBufferFTV or \ref GX2InitColorBuffer. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void _GX2InitColorBuffer(GX2ColorBuffer *colorBuffer, u32 width, u32 height, GX2SurfaceFormat format, GX2AAMode aa) { GX2_CHECK_ENUM_RANGE(format, GX2_SURFACE_FORMAT) GX2_CHECK_ENUM_RANGE(aa, GX2_AA_MODE) colorBuffer->surface.dim = GX2_SURFACE_DIM_2D; colorBuffer->surface.width = width; colorBuffer->surface.height = height; colorBuffer->surface.depth = 1; colorBuffer->surface.numMips = 1; // 1 means base level only colorBuffer->surface.mipPtr = NULL; colorBuffer->surface.format = format; colorBuffer->surface.aa = aa; // colorBuffer->surface.use set by wrapping function #ifdef GX2_ENABLE_FIX2197 colorBuffer->surface.tileMode = GX2_TILE_MODE_DEFAULT_FIX2197; #else colorBuffer->surface.tileMode = GX2_TILE_MODE_DEFAULT; #endif colorBuffer->surface.swizzle = 0; colorBuffer->viewMip = 0; colorBuffer->viewFirstSlice = 0; colorBuffer->viewNumSlices = 1; GX2CalcSurfaceSizeAndAlignment(&colorBuffer->surface); #ifndef GX2_SURFACE_STANDALONE GX2InitColorBufferRegs(colorBuffer); #endif } /// \brief Helper function to set up color buffer structure in a convenient way. /// /// \note Certain fields are set to typical default values. If you wish to non-default /// values, then those fields must be set manually. You may need to call /// \ref GX2CalcSurfaceSizeAndAlignment or \ref GX2InitColorBufferRegs after /// changing certain fields. /// /// \param colorBuffer Ptr to color buffer structure to initialize. /// \param width Desired width for color buffer. /// \param height Desired height for color buffer. /// \param format Desired surface format for color buffer. /// \param aa Desired AA mode for color buffer. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2InitColorBuffer(GX2ColorBuffer *colorBuffer, u32 width, u32 height, GX2SurfaceFormat format, GX2AAMode aa) { colorBuffer->surface.use = GX2_SURFACE_USE_COLOR_BUFFER_TEXTURE; _GX2InitColorBuffer(colorBuffer, width, height, format, aa); } /// \brief Helper function to set up color buffer image pointer. /// /// \note This function only changes the image pointer, not the mip pointer, /// which is normally not relevant to color buffers unless you're rendering to a mip level. /// /// \param colorBuffer Ptr to color buffer structure to update. /// \param ptr New image pointer value. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2InitColorBufferPtr(GX2ColorBuffer *colorBuffer, void *ptr) { colorBuffer->surface.imagePtr = ptr; } /// \brief Helper function to set up color buffer aux (AA) pointer. /// /// \note This function only needs to be called for AA surfaces. /// AA surfaces must have an aux buffer set up. /// \note The auxPtr buffer must be initialized to \ref GX2_AUX_BUFFER_CLEAR_VALUE. /// /// \param colorBuffer Ptr to color buffer structure to update. /// \param auxPtr New aux buffer pointer value. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2InitColorBufferAuxPtr(GX2ColorBuffer *colorBuffer, void *auxPtr) { colorBuffer->auxPtr = auxPtr; } /// \brief Helper function to set up color buffer that is a final TV render target. /// /// A "final" TV render target is one that will be copied to a TV scan buffer. /// It needs to be designated to handle certain display corner cases. /// (When a HD surface must be scaled down to display in NTSC/PAL.) /// /// In cases when the surface must be scaled down for proper display, /// if the requested surface was AA, then AA will be disabled. /// This is required to work around certain hardware limitations /// (this avoids performance penalties from other possible work-arounds). /// To see if AA was disabled, check the value of the surface->aa field /// after making this call. /// /// An alternate solution to having the AA disabled is to instead choose a /// final TV render target size that matches the reduced-size scan buffer. /// See the \ref GX2DisplayPage page for details. /// /// \note Certain fields are set to typical default values. If you wish to non-default /// values, then those fields must be set manually. You may need to call /// \ref GX2CalcSurfaceSizeAndAlignment or \ref GX2InitColorBufferRegs after /// changing certain fields. /// /// \param colorBuffer Ptr to color buffer structure to initialize. /// \param width Desired width for color buffer. /// \param height Desired height for color buffer. /// \param format Desired surface format for color buffer. /// \param aa Desired AA mode for color buffer. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2InitColorBufferFTV(GX2ColorBuffer *colorBuffer, u32 width, u32 height, GX2SurfaceFormat format, GX2AAMode aa) { colorBuffer->surface.use = GX2_SURFACE_USE_COLOR_BUFFER_TEXTURE_FTV; _GX2InitColorBuffer(colorBuffer, width, height, format, aa); // If aa was disabled, pad size/align to what aa would have required if (colorBuffer->surface.aa != aa) { GX2Surface paddedSurf = colorBuffer->surface; paddedSurf.aa = aa; paddedSurf.use = GX2_SURFACE_USE_COLOR_BUFFER_TEXTURE; GX2CalcSurfaceSizeAndAlignment(&paddedSurf); ASSERT(colorBuffer->surface.imageSize <= paddedSurf.imageSize); ASSERT(colorBuffer->surface.alignment <= paddedSurf.alignment); colorBuffer->surface.imageSize = paddedSurf.imageSize; colorBuffer->surface.alignment = paddedSurf.alignment; } } /// @} /// @addtogroup GX2SurfaceDepthGroup /// @{ /// \brief Helper function to set up depth buffer structure in a convenient way. /// /// \note Certain fields are set to typical default values. If you wish to non-default /// values, then those fields must be set manually. You may need to call /// \ref GX2CalcSurfaceSizeAndAlignment or \ref GX2InitDepthBufferRegs after /// changing certain fields. /// /// \param depthBuffer Ptr to depth buffer structure to initialize. /// \param width Desired width for depth buffer. /// \param height Desired height for depth buffer. /// \param format Desired surface format for depth buffer. /// \param aa Desired AA mode for depth buffer. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2InitDepthBuffer(GX2DepthBuffer *depthBuffer, u32 width, u32 height, GX2SurfaceFormat format, GX2AAMode aa) { GX2_CHECK_ENUM_RANGE(format, GX2_SURFACE_FORMAT) GX2_CHECK_ENUM_RANGE(aa, GX2_AA_MODE) depthBuffer->surface.dim = GX2_SURFACE_DIM_2D; depthBuffer->surface.width = width; depthBuffer->surface.height = height; depthBuffer->surface.depth = 1; depthBuffer->surface.numMips = 1; // 1 means base level only depthBuffer->surface.format = format; depthBuffer->surface.aa = aa; depthBuffer->surface.use = ((format==GX2_SURFACE_FORMAT_D_D24_S8_UNORM) || (format==GX2_SURFACE_FORMAT_D_D24_S8_FLOAT)) ? GX2_SURFACE_USE_DEPTH_BUFFER : GX2_SURFACE_USE_DEPTH_BUFFER_TEXTURE; depthBuffer->surface.tileMode = GX2_TILE_MODE_DEFAULT; depthBuffer->surface.swizzle = 0; depthBuffer->viewMip = 0; depthBuffer->viewFirstSlice = 0; depthBuffer->viewNumSlices = 1; depthBuffer->hiZPtr=NULL; depthBuffer->hiZSize=0; depthBuffer->clearDepth = 1.0f; depthBuffer->clearStencil = 0; GX2CalcSurfaceSizeAndAlignment(&depthBuffer->surface); #ifndef GX2_SURFACE_STANDALONE GX2InitDepthBufferRegs(depthBuffer); #endif } /// \brief Helper function to set up depth buffer image pointer /// /// \note This function only changes the image pointer, not the mip pointer, /// which is normally not relevant to depth buffers unless you're rendering to a mip level. /// /// \param depthBuffer Ptr to depth buffer structure to update. /// \param ptr New image pointer value. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2InitDepthBufferPtr(GX2DepthBuffer *depthBuffer, void *ptr) { depthBuffer->surface.imagePtr = ptr; } /// \brief Helper function to set up depth buffer Hi-Z pointer. /// /// Hierarchical Z-buffer is optional; it improves depth testing performance. /// /// \param depthBuffer Ptr to depth buffer structure to update. /// \param hiZPtr New Hi-Z buffer pointer value. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2InitDepthBufferHiZPtr(GX2DepthBuffer *depthBuffer, void *hiZPtr) { depthBuffer->hiZPtr = hiZPtr; GX2InitDepthBufferHiZEnable(depthBuffer, (GX2Boolean)(hiZPtr != NULL)); } /// @} /// @addtogroup GX2SurfaceCopyGroup /// @{ /// \brief Copies the specified source surface to dest surface. /// /// Only copies a single 2D mip slice at most. The copy will be done by /// the GPU, unless a surface uses LINEAR_SPECIAL tile format, in which case /// a CPU copy is performed. For CPU copies, you may need to synchronize with /// the GPU (by calling \ref GX2DrawDone, for instance). /// /// \note This API may change rendering states and disable state shadowing. /// It may alter registers that cannot be restored by common GX2 functions. /// Therefore you should always call \ref GX2SetContextState() afterward /// (except when doing CPU copies). /// /// \note The source and destinations surfaces must be the same format and have /// the same dimensions. Stretching is not supported. /// /// \note Copying of format GX2_SURFACE_FORMAT_T_NV12_UNORM is currently not /// supported. /// /// \note Compressed textures must be copied on a 4x4 pixel alignment. /// Coordinates are in terms of pixels, not blocks. /// /// \note CPU copies are very slow and should normally be avoided. /// /// \param srcSurface Pointer to source surface structure /// \param srcMip Mip level of surface to read (0 typically) /// \param srcSlice Slice to read for array & 3D (0 typically) /// \param dstSurface Pointer to destination surface structure /// \param dstMip Mip level of dest surface to write (0 typically) /// \param dstSlice Slice to write for array & 3D (0 typically) /// /// \donotcall \gx2_typical \enddonotcall /// /// \clobberstate If source or destination mode are GX2_TILE_MODE_LINEAR_SPECIAL this does not clobber state. /// \disablesstateshadow If source or destination mode are GX2_TILE_MODE_LINEAR_SPECIAL this does not disable state shadowing. /// \notincompute /// /// \writesgpu /// \writesgpu{if source and destination tiling modes are not \ref GX2_TILE_MODE_LINEAR_SPECIAL} /// void GX2API GX2CopySurface(const GX2Surface *srcSurface, u32 srcMip, u32 srcSlice, GX2Surface *dstSurface, u32 dstMip, u32 dstSlice); /// \brief Copies the specified source surface sub-rectangles to the dest surface at specified points. /// /// Only copies from and to a single 2D mip slice at most. This API does not support buffers that use /// LINEAR_SPECIAL tiling. All operations are performed using the GPU. /// /// \note This API may change rendering states and disable state shadowing. /// It may alter registers that cannot be restored by common GX2 functions. /// Therefore you should always call \ref GX2SetContextState() afterward /// (except when doing CPU copies). /// /// \note The source and destinations surfaces must be the same format and /// stretching is not supported. /// /// \note The source rectangles and destination points should be in dimensions /// relative to srcMip/dstMip and not the base level. /// For example, if the base level of the texture is 100x100 and you /// wanted to copy all of srcMip = 1, then the source /// rectangle would be from (0,0) to (50x50), since the size of the src /// mip is 50 (100/2) on each side. /// /// \note Copying of format GX2_SURFACE_FORMAT_T_NV12_UNORM is currently not /// supported. /// /// \note CPU copies are very slow and should normally be avoided. /// /// \param srcSurface Pointer to source surface structure /// \param srcMip Mip level of surface to read (0 typically) /// \param srcSlice Slice to read for array & 3D (0 typically) /// \param dstSurface Pointer to destination surface structure /// \param dstMip Mip level of dest surface to write (0 typically) /// \param dstSlice Slice to write for array & 3D (0 typically) /// \param numRects The number of source rectangles and destination points that describe the sub-regions to copy (1 typically). /// This number cannot be larger than GX2_MAX_COPY_SURFACE_EX_RECTS. /// \param pSrcRects A pointer to an array of source rectangles describing the region of srcSurface to copy from. /// \param pDstPoints A pointer to an array of destination points describing the locations in dstSurface to copy to. /// /// \donotcall \gx2_typical \enddonotcall /// /// \clobberstate /// \disablesstateshadow /// \notincompute /// /// \writesgpu /// \writesgpu{if source and destination tiling modes are not \ref GX2_TILE_MODE_LINEAR_SPECIAL} /// void GX2API GX2CopySurfaceEx(const GX2Surface *srcSurface, u32 srcMip, u32 srcSlice, GX2Surface *dstSurface, u32 dstMip, u32 dstSlice, u32 numRects, GX2RectInt *pSrcRects, GX2PointInt *pDstPoints); /// @} /// @addtogroup GX2SurfaceTileGroup /// @{ /// \brief Allocates a tiling aperture which allows linear CPU access to a tiled surface. /// /// To access a pixel/texel in the linear view, use: /// - pixel address = aperture address + (Y * surface.pitch + X) * bytes_per_pixel /// /// Note that reading/writing through the tiling aperture is slower than referring to /// the tiled surface directly. For just checking a few pixels, this is reasonable. /// To read/write an entire surface, it is suggested to use a LINEAR_ALIGNED surface /// instead, and have the GPU convert the linear surface to or from a tiled format. /// /// \note After writing to a tiling aperture, a "flush" operation is REQUIRED. The /// flush is performed by simply reading back an address within the aperture. /// It ensures that the data has made it to memory, and it also is necessary /// to prevent a corruption issue that can occur with any GX2 commands that /// follow. The flush must therefore be done after any tiling aperture writes /// and before calling any GX2 APIs that write out GPU commands. /// /// \note Only ~30 tiling apertures may be created simultaneously. They should be freed /// (using \ref GX2FreeTilingAperture) after they are no longer needed. /// Calling \ref GX2FreeTilingAperture will perform the flush mentioned above. /// /// \note There is also a limit of ~256MB of aperture space that may be allocated /// at once. (This limit may vary in the future.) /// /// \note There is a hardware bug for 1-byte pixel formats. The required work-around /// is to invert two of the address bits when accessing such a surface via the /// the tiling aperture: /// - pixel address = aperture address + ((Y^2) * surface.pitch + (X^8)) /// /// \note The tiling APIs are not reentrant (that is, they are not multicore safe). You should either /// only call them from a single core, or else add a mutex around calls to them. /// /// \param pSurface Pointer to surface structure to be accessed /// \param mip Which mip level to view (for textures only, otherwise use 0) /// \param slice Which 3D/array slice to view (as appropriate, otherwise use 0) /// \param mode Enable endian swap for this area's CPU read/write /// \param pAppHandle Returned handle to use when freeing tiling aperture /// \param pAppAddress Returned base address to use when accessing surface linearly /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \directwritesgpu /// void GX2API GX2AllocateTilingApertureEx(const GX2Surface *pSurface, u32 mip, u32 slice, GX2EndianSwapMode mode, u32 *pAppHandle, void **pAppAddress); /// \brief Allocates a tiling aperture which allows linear CPU access to a tiled surface. /// /// This is an inline function that calls \ref GX2AllocateTilingApertureEx with the endian /// swap mode set to \ref GX2_ENDIANSWAP_NONE. /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \directwritesgpu /// GX2_INLINE void GX2AllocateTilingAperture(const GX2Surface *pSurface, u32 mip, u32 slice, u32 *pAppHandle, void **pAppAddress) { GX2AllocateTilingApertureEx(pSurface, mip, slice, GX2_ENDIANSWAP_NONE, pAppHandle, pAppAddress); } /// \brief Frees a tiling aperture which allows linear CPU access to a tiled surface. /// /// \param appHandle Handle to tiling aperture to free /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \directwritesgpu /// void GX2API GX2FreeTilingAperture(u32 appHandle); /// @} /// @addtogroup GX2SurfaceCopyGroup /// @{ /// \brief Resolves an MSAA color buffer to a single-sample color surface by /// averaging the multiple sample colors together. The source buffer is not modified. /// /// This resolve will use the GPU's fast fixed-function hardware to perform the resolve, /// however only certain formats are supported. See the function \ref GX2IsResolveSupported() /// to see which formats support this fixed-function resolve path. Calling this function with /// an unsupported format will assert in a debug build, but result in undefined behavior in a /// release build. To perform an MSAA resolve on a format that is not supported by the /// fixed-function resolve hardware, do not use this function, but instead use a custom shader /// to blend the MSAA samples (see test\gx2\assets\shaders\simple\texture2DMS.ps) in a draw. /// /// If srcBuffer contains multiple slices, they will all be resolved to /// the dstSurface beginning at dstSlice. This function resolves only the single /// miplevel specified by srcBuffer->viewMip and dstMip. This function resolves the number of /// slices specified by srcBuffer->viewNumSlices starting with slice number /// srcBuffer->viewFirstSlice. /// /// \note This API changes rendering states and disables state shadowing. /// It may alter registers that cannot be restored by common GX2 functions. /// Therefore you should always call \ref GX2SetContextState() afterward. /// /// \param srcBuffer Pointer to a compressed MSAA color buffer /// \param dstSurface Pointer to a single-sample surface /// \param dstMip Which mip level to write /// \param dstSlice Which 3D/array slice to start writing to /// /// \donotcall \gx2_typical \enddonotcall /// /// \clobberstate /// \disablesstateshadow /// \notincompute /// /// \writesgpu /// \alwayswritesgpu /// void GX2API GX2ResolveAAColorBuffer(const GX2ColorBuffer *srcBuffer, GX2Surface *dstSurface, u32 dstMip, u32 dstSlice); /// \brief Expands an MSAA color buffer in-place to allow the surface to be /// used as an MSAA texture. /// /// It is not necessary to call this function before calling \ref GX2ResolveAAColorBuffer. /// This function modifies both the MSAA buffer and its auxiliary memory. /// Subsequent draw calls to this buffer will undo the expand, so this must be /// called between drawing to the buffer and texturing from it. It is okay to /// draw to this buffer after expanding it. /// /// All slices referred to by buffer->viewFirstSlice and /// buffer->viewNumSlices will be expanded. This function resolves only the single /// miplevel specified by buffer->viewMip. /// /// \note This API changes rendering states and disables state shadowing. /// It may alter registers that cannot be restored by common GX2 functions. /// Therefore you should always call \ref GX2SetContextState() afterward. /// /// \param buffer Pointer to a compressed MSAA color buffer /// /// \donotcall \gx2_typical \enddonotcall /// /// \clobberstate /// \disablesstateshadow /// \notincompute /// /// \writesgpu /// \alwayswritesgpu /// void GX2API GX2ExpandAAColorBuffer(GX2ColorBuffer *buffer); /// \brief Expands a HiZ depth buffer in-place. /// /// Prepares a HiZ depth buffer to be used as a texture. For the surface /// to be usable as a texture it must have a \ref GX2SurfaceFormat that /// is compatible with use as a texture. For example, /// \ref GX2_SURFACE_FORMAT_D_D24_S8_UNORM cannot be used as a texture. /// In addition, the depth-format texture must not be MSAA. If you must /// texture from D24_S8 format or MSAA depth data, then you must call /// \ref GX2ConvertDepthBufferToTextureSurface instead. /// /// This function modifies both the depth buffer and its HiZ buffer. /// Subsequent draw calls to this buffer will undo the expand, so this must be /// called between drawing to the buffer and texturing from it. It is fine to /// draw to this buffer after expanding it. /// /// All slices referred to by buffer->viewFirstSlice and /// buffer->viewNumSlices will be expanded. This function resolves only the single /// miplevel specified by buffer->viewMip. /// /// \note This API changes rendering states and disables state shadowing. /// It may alter registers that cannot be restored by common GX2 functions. /// Therefore you should always call \ref GX2SetContextState() afterward. /// /// \param buffer Pointer to a HiZ depth buffer structure /// /// \donotcall \gx2_typical \enddonotcall /// /// \clobberstate /// \disablesstateshadow /// \notincompute /// /// \writesgpu /// \alwayswritesgpu /// void GX2API GX2ExpandDepthBuffer(GX2DepthBuffer *buffer); /// \brief Copies and converts a depth buffer to a format readable as a texture. /// /// Copies a depth buffer (with or without HiZ) to another surface while /// changing from depth-format tiling to texture/color-format tiling. /// This is only necessary for depth formats that cannot already be read /// by the texture unit (those with AA or D24_S8 format). This is also /// necessary if you wish to convert a depth buffer directly into a color /// buffer. The number of MSAA samples in the source and destination must /// match. /// /// The surface dstSurface must not have a use of GX2_SURFACE_USE_DEPTH_BUFFER /// as this API will convert the surface tiling to only be suitable for uses /// of GX2_SURFACE_USE_TEXTURE or GX2_SURFACE_USE_COLOR_BUFFER. /// /// Converting 'in-place' can be achieved if the source and destination surfaces /// have the same memory pointers. The 'use' field in the source and /// destination surfaces must be set differently and correctly (USE_DEPTH_BUFFER /// for the source and !USE_DEPTH_BUFFER and [USE_TEXTURE or USE_COLOR_BUFFER] /// for the destination). When copying 'in-place', the 'tileMode' must be /// the same for the source and destination. /// /// If the HiZ buffer is present, the depth data will be expanded during the /// conversion. When the conversion is not 'in-place', the source depth /// and HiZ buffers will not be modified and it is fine to draw to the source /// buffer after this operation. /// /// If srcBuffer contains multiple slices, they will all be expanded to /// the dstSurface beginning at dstSlice. This function resolves only the single /// miplevel specified by srcBuffer->viewMip and dstMip. This function resolves /// the number of slices specified by srcBuffer->viewNumSlices starting with slice /// number srcBuffer->viewFirstSlice. /// /// The result of calling GX2ConvertDepthBufferToTextureSurface() on a /// D_D24_S8_UNORM depth buffer is a D24_S8 buffer, with both depth and stencil /// bits, that can be read by the texture unit. (It is NOT necessary to call /// GX2ConvertDepthBufferToTextureSurface() twice on the D_D24_S8_UNORM to get both /// the depth and stencil data.) However, because the D24 depth data is 24-bits in /// UNORM format and then S8 stencil data is 8-bits in UINT format, a single /// texture sampler can only read one or the other (depth OR stencil data). The /// GX2_SURFACE_FORMAT_T_R24_UNORM_X8 and GX2_SURFACE_FORMAT_T_X24_G8_UINT values /// are used to indicate the two formats used for reading the buffer, but the /// buffer always contains both the depth and stencil data. /// /// The render2depth demo shows how to read the depth and stencil data from the /// buffer, but does so in two different draw calls. By using the same GX2Surface, /// pointing to the same memory buffer, setting the format field to either /// T_R24_UNORM_X8 or T_X24_G8_UINT simply selects in which format the bits will be /// read out of the buffer. The GX2Texture structure's "compSel" field is used to /// read the depth data out of the X channel (GX2_COMP_SEL_XXXX) or the stencil /// data out of the Y channel (GX2_COMP_SEL_YYYY). It is also possible to read the /// depth and stencil data from the memory buffer in a single draw call as long as /// you setup two GX2Surface structures, two different samplers, "bind" the /// converted depth buffer to both, and perform two texture fetches. /// /// If converting a GX2_SURFACE_FORMAT_D_D24_S8_UNORM buffer using /// GX2ConvertDepthBufferToTextureSurface(), set the destination format to /// GX2_SURFACE_FORMAT_T_R24_UNORM_X8. If converting a /// GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24 buffer using /// GX2ConvertDepthBufferToTextureSurface(), set the destination format to /// GX2_SURFACE_FORMAT_T_R32_FLOAT_X8_X24. /// /// \note This API changes rendering states and disables state shadowing. /// It may alter registers that cannot be restored by common GX2 functions. /// Therefore you should always call \ref GX2SetContextState() afterward. /// /// \param srcBuffer Pointer to a depth buffer structure /// \param dstSurface Pointer to a destination surface structure /// \param dstMip Mip level of destination surface to write /// \param dstSlice Slice to begin writing source slices to /// /// \donotcall \gx2_typical \enddonotcall /// /// \clobberstate /// \disablesstateshadow /// \notincompute /// /// \writesgpu /// \alwayswritesgpu /// void GX2API GX2ConvertDepthBufferToTextureSurface(const GX2DepthBuffer *srcBuffer, GX2Surface *dstSurface, u32 dstMip, u32 dstSlice); /// @} /// @addtogroup GX2SurfaceColorGroup /// @{ /// \brief Given an NV12 format surface, create a surface structure that refers /// to the UV plane of the NV12 surface. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE void GX2InitNV12UVSurface(GX2Surface *dstUVSurface, GX2Surface *srcNV12Surface) { ASSERT(srcNV12Surface && dstUVSurface); ASSERT(srcNV12Surface->format == GX2_SURFACE_FORMAT_T_NV12_UNORM); *dstUVSurface = *srcNV12Surface; dstUVSurface->height >>= 1; dstUVSurface->width >>= 1; dstUVSurface->pitch >>= 1; dstUVSurface->format = GX2_SURFACE_FORMAT_TC_R8_G8_UNORM; dstUVSurface->imagePtr = (void*)((u32)dstUVSurface->imagePtr + srcNV12Surface->mipOffset[0]); dstUVSurface->imageSize -= srcNV12Surface->mipOffset[0]; } /// @} /// @addtogroup GX2SurfaceAllGroup /// @{ /// \brief Returns the size in bits per pixel for a given surface format. /// For block compressed formats, it returns the "effective" bits per pixel (bits per block/pixels per block). /// /// \donotcall \threadsafe \devonly \enddonotcall /// u32 GX2API GX2GetSurfaceFormatBits(GX2SurfaceFormat format); /// \brief Given a surface pointer and mip level, returns the swizzle offset. /// If a surface is not compatible with swizzling, then 0 will be returned, even if /// surface->swizzle is non-zero. /// /// \param surface Ptr to surface structure. /// \param mipLevel Mip level referenced. /// \return The Swizzle offset. /// /// \donotcall \threadsafe \devonly \enddonotcall /// u32 GX2API GX2GetSurfaceSwizzleOffset(GX2Surface *surface, u32 mipLevel); /// \brief Given a surface pointer, returns the swizzle that was set for that surface through /// GX2SetSurfaceSwizzle(). If a non-zero swizzle was set through GX2SetSurfaceSwizzle(), /// then GX2GetSurfaceSwizzle() will return the same non-zero swizzle even if the surface /// is not compatible with swizzling. /// /// \param surface Ptr to surface structure. /// \return The Swizzle value. /// /// \donotcall \threadsafe \devonly \enddonotcall /// u32 GX2API GX2GetSurfaceSwizzle(GX2Surface *surface); /// \brief Helper function to set the swizzle value on a given surface. /// /// \note Changing the swizzle value will cause all of the current contents of the buffer to appear corrupted if read. /// /// \param surface Ptr to surface structure. /// \param swizzle Desired swizzle value. /// /// \donotcall \threadsafe \devonly \enddonotcall /// void GX2API GX2SetSurfaceSwizzle(GX2Surface *surface, u32 swizzle); /// \brief Given a surface pointer and mip level, returns the mip pitch in pixels. /// /// \note For compressed formats, the pitch is in "elements" (4x4 pixel blocks). /// /// \param surface Ptr to surface structure. /// \param mipLevel Mip level referenced. /// \return The mip pitch in pixels or elements. /// /// \donotcall \threadsafe \devonly \enddonotcall /// u32 GX2API GX2GetSurfaceMipPitch(GX2Surface *surface, u32 mipLevel); /// \brief Given a surface pointer and mip level, returns the slice size in bytes. /// /// Returns (aligned_width * aligned_height * bytes_per_pixel * samples). /// The "aligned width" is equivalent to "pitch". /// /// \note A "slice" here is always a 2D slice. /// /// \param surface Ptr to surface structure. /// \param mipLevel Mip level referenced. /// \return The slice size in bytes. /// /// \donotcall \threadsafe \devonly \enddonotcall /// u32 GX2API GX2GetSurfaceMipSliceSize(GX2Surface *surface, u32 mipLevel); /// \brief Given a surface pointer and mip level, return the number of depth slices at that mip level. /// /// \param surface Ptr to surface structure. /// \param mipLevel Mip level referenced, where 0 is the first mip level. /// \return The number of max valid depth slices at that mip level. 1 is the smallest returned value. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2_INLINE u32 GX2GetSurfaceMipDepth(const GX2Surface *surface, u32 mipLevel) { ASSERT(surface); ASSERT(mipLevel < surface->numMips); if(surface->dim != GX2_SURFACE_DIM_3D) { return surface->depth; } else { //For 3D surfaces, the number of depth slices decreases with miplevel. u32 depth = surface->depth >> mipLevel; //Returned depth should never be smaller than 1. return (depth >= 1) ? depth : 1; } } /// \brief Given a surface format, return GX2_TRUE if the format is a block compressed format (i.e. BC1). /// /// \param format A surface format /// \return GX2_TRUE if the format is a block compressed format and GX2_FALSE otherwise. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2Boolean GX2API GX2SurfaceIsCompressed(GX2SurfaceFormat format); /// \brief Given a surface format and use, return GX2_TRUE if the format is compatible with the use. /// /// \param use A surface use /// \param format A surface format /// \return GX2_TRUE if the format is compatible with the use and GX2_FALSE otherwise. /// \note "D" and "S" uses may not always be reported correctly. /// /// \donotcall \threadsafe \devonly \enddonotcall /// GX2Boolean GX2API GX2CheckSurfaceUseVsFormat(GX2SurfaceUse use, GX2SurfaceFormat format); /// \brief Sets the AA mode. /// /// This function sets the AA mode and can be used in conjunction /// with \ref GX2SetDepthBuffer() to setup depth only rendering. /// /// \note The AA mode is also set by \ref GX2SetColorBuffer() when the target /// is GX2_RENDER_TARGET_0 or by \ref GX2UTSetRenderTargets(). /// /// \param aa AA Mode to set \ref GX2AAMode. /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// void GX2API GX2SetAAMode(GX2AAMode aa); /// \brief Sets the AA mode with custom AA location. /// /// This function sets the AA mode and AA position and can be used in /// conjunction with \ref GX2SetDepthBuffer() to setup depth only rendering. /// /// \note All entries should be populated when MSAA is in use. This API /// automatically fills all entries by repeating user specified sample /// positions.(first two in GX2_AA_MODE_2X and four in GX2_AA_MODE_4X). /// \note The AA mode is also set by \ref GX2SetColorBuffer() when the target /// is GX2_RENDER_TARGET_0 or by \ref GX2UTSetRenderTargets(). /// This API must be called afterward to customize the AA locations. /// /// \param sampleLoc AA location (up to x8 samples). Each sample ranges -8/16 to 7/16 offset from pixel center. /// \param aa AA Mode to set \ref GX2AAMode. /// /// \donotcall \gx2_typical \enddonotcall /// /// \writesgpu /// \alwayswritesgpu /// void GX2API GX2SetAAModeEx(GX2AASampleLoc* sampleLoc, GX2AAMode aa); /// @} /// @} #ifdef __cplusplus } #endif #endif // _CAFE_GX2_SURFACE_H_