3665 lines
133 KiB
C++
3665 lines
133 KiB
C++
![]() |
/**********************************************************************
|
||
|
|
||
|
Filename : GRendererPS3Impl.cpp
|
||
|
Content : PS3 libgcm Sample renderer implementation
|
||
|
Created : 1 February 2007
|
||
|
Authors : Andrew Reisse
|
||
|
|
||
|
Copyright : (c) 2007 Scaleform Corp. All Rights Reserved.
|
||
|
|
||
|
Notes :
|
||
|
|
||
|
Licensees may use this file in accordance with the valid Scaleform
|
||
|
Commercial License Agreement provided with the software.
|
||
|
|
||
|
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
|
||
|
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
|
||
|
|
||
|
**********************************************************************/
|
||
|
|
||
|
|
||
|
#include "GImage.h"
|
||
|
|
||
|
#include "GRendererPS3.h"
|
||
|
#include "GRendererCommonImpl.h"
|
||
|
|
||
|
#include <string.h> // for memset()
|
||
|
|
||
|
#include <cell/fs/cell_fs_file_api.h>
|
||
|
#include <cell/gcm.h>
|
||
|
#include <sys/paths.h>
|
||
|
|
||
|
// ***** Classes implemented
|
||
|
class GRendererPS3Impl;
|
||
|
class GTexturePS3Impl;
|
||
|
|
||
|
|
||
|
// Define this macro if mask should be implemented through
|
||
|
// z-buffer instead of stencil. Will overwrite z-buffer contents.
|
||
|
// #define GFC_ZBUFFER_MASKING
|
||
|
|
||
|
|
||
|
// Pixel shaders
|
||
|
enum PixelShaderType
|
||
|
{
|
||
|
PS_None = 0,
|
||
|
PS_Solid,
|
||
|
PS_TextTexture,
|
||
|
PS_TextTextureColor,
|
||
|
PS_TextTextureColorMultiply,
|
||
|
PS_TextTextureYUV,
|
||
|
PS_TextTextureYUVMultiply,
|
||
|
PS_TextTextureYUVA,
|
||
|
PS_TextTextureYUVAMultiply,
|
||
|
PS_CxformTexture,
|
||
|
PS_CxformTextureMultiply,
|
||
|
|
||
|
PS_CxformGouraud,
|
||
|
PS_CxformGouraudNoAddAlpha,
|
||
|
PS_CxformGouraudTexture,
|
||
|
PS_Cxform2Texture,
|
||
|
|
||
|
// Multiplies - must come in same order as other gourauds
|
||
|
PS_CxformGouraudMultiply,
|
||
|
PS_CxformGouraudMultiplyNoAddAlpha,
|
||
|
PS_CxformGouraudMultiplyTexture,
|
||
|
PS_CxformMultiply2Texture,
|
||
|
|
||
|
PS_CmatrixTexture,
|
||
|
PS_BlurFilter,
|
||
|
PS_ShadowFilter,
|
||
|
PS_ShadowKoFilter,
|
||
|
PS_ShadowOnlyFilter,
|
||
|
PS_Blur1Filter,
|
||
|
PS_Shadow1Filter,
|
||
|
PS_ShadowKo1Filter,
|
||
|
PS_ShadowOnly1Filter,
|
||
|
|
||
|
PS_Count
|
||
|
};
|
||
|
|
||
|
#include "PS3/PS3Shaders.h"
|
||
|
|
||
|
|
||
|
struct CgShader
|
||
|
{
|
||
|
CGprogram prog;
|
||
|
GAllocatorPS3::Handle memobj;
|
||
|
UInt32 offset;
|
||
|
CGparameter cxmul, cxadd;
|
||
|
CGparameter tex[6];
|
||
|
UInt texi[6];
|
||
|
|
||
|
CGparameter uniforms[FSU_Count];
|
||
|
};
|
||
|
|
||
|
struct CgVProgram
|
||
|
{
|
||
|
CGprogram prog;
|
||
|
void* uc;
|
||
|
CGparameter mvp;
|
||
|
CGparameter texgenx[2], texgeny[2];
|
||
|
CGparameter pos, tc, color, factor;
|
||
|
UInt posi, tci, colori, factori;
|
||
|
};
|
||
|
|
||
|
/* Compiled shaders */
|
||
|
extern int _binary_p_cxform_fpo_start;
|
||
|
extern int _binary_p_cxformmul_fpo_start;
|
||
|
extern int _binary_p_cxg2t_fpo_start;
|
||
|
extern int _binary_p_cxg2tm_fpo_start;
|
||
|
extern int _binary_p_cxg_fpo_start;
|
||
|
extern int _binary_p_cxgm_fpo_start;
|
||
|
extern int _binary_p_cxgmna_fpo_start;
|
||
|
extern int _binary_p_cxgna_fpo_start;
|
||
|
extern int _binary_p_cxgt_fpo_start;
|
||
|
extern int _binary_p_cxgtm_fpo_start;
|
||
|
extern int _binary_p_solid_fpo_start;
|
||
|
extern int _binary_p_text_fpo_start;
|
||
|
extern int _binary_p_texta_fpo_start;
|
||
|
extern int _binary_p_textmul_fpo_start;
|
||
|
extern int _binary_v_1tex_vpo_start;
|
||
|
extern int _binary_v_2tex_vpo_start;
|
||
|
extern int _binary_v_text_vpo_start;
|
||
|
|
||
|
#ifndef GFC_NO_YUV_TEXTURES
|
||
|
extern int _binary_p_cxformyuv_fpo_start;
|
||
|
extern int _binary_p_cxformyuvmul_fpo_start;
|
||
|
extern int _binary_p_cxformyuva_fpo_start;
|
||
|
extern int _binary_p_cxformyuvamul_fpo_start;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// ***** GTexturePS3Impl implementation
|
||
|
|
||
|
|
||
|
// GTexturePS3Impl declaration
|
||
|
class GTexturePS3Impl : public GTexturePS3
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// Renderer
|
||
|
GRendererPS3Impl* pRenderer;
|
||
|
// texture data
|
||
|
Handle TexMem;
|
||
|
CellGcmTexture Tex;
|
||
|
|
||
|
GTexturePS3Impl(GRendererPS3Impl *prenderer);
|
||
|
~GTexturePS3Impl();
|
||
|
|
||
|
// Obtains the renderer that create TextureInfo
|
||
|
virtual GRenderer* GetRenderer() const;
|
||
|
virtual bool IsDataValid() const;
|
||
|
|
||
|
// Creates a texture based on parameters
|
||
|
virtual bool InitTexture(CellGcmTexture *pTex, bool unused = 0);
|
||
|
virtual bool InitTexture(GImageBase* pim, UInt usage = Usage_Wrap);
|
||
|
|
||
|
virtual bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage);
|
||
|
virtual void Update(int level, int n, const UpdateRect *rects, const GImageBase *pim);
|
||
|
|
||
|
virtual int Map(int level, int n, MapRect* maps, int flags);
|
||
|
virtual bool Unmap(int level, int n, MapRect* maps, int flags);
|
||
|
|
||
|
virtual CellGcmTexture* GetNativeTexture() const { return const_cast<CellGcmTexture*>(&Tex); }
|
||
|
|
||
|
// Releases texture and clears vals
|
||
|
virtual void ReleaseTexture();
|
||
|
|
||
|
// Remove texture from renderer, notifies of renderer destruction
|
||
|
void RemoveFromRenderer();
|
||
|
|
||
|
virtual int IsYUVTexture() { return 0; }
|
||
|
virtual void Bind(int stage, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps);
|
||
|
};
|
||
|
|
||
|
#ifndef GFC_NO_YUV_TEXTURES
|
||
|
|
||
|
class GTexturePS3ImplYUV : public GTexturePS3Impl
|
||
|
{
|
||
|
CellGcmTexture TexUVA[3];
|
||
|
Handle TexMemUVA[3];
|
||
|
|
||
|
public:
|
||
|
GTexturePS3ImplYUV (GRendererPS3Impl *prenderer);
|
||
|
~GTexturePS3ImplYUV();
|
||
|
|
||
|
virtual bool InitTexture(CellGcmTexture *pTex) { return 0; }
|
||
|
virtual bool InitTexture(GImageBase* pim, UInt) { return 0; }
|
||
|
virtual bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage);
|
||
|
virtual void Update(int level, int n, const UpdateRect *rects, const GImageBase *pim) { }
|
||
|
|
||
|
virtual int Map(int level, int n, MapRect* maps, int flags);
|
||
|
virtual bool Unmap(int level, int n, MapRect* maps, int flags);
|
||
|
|
||
|
virtual void ReleaseTexture();
|
||
|
|
||
|
virtual int IsYUVTexture() { return TexMemUVA[2] ? 2 : 1; }
|
||
|
virtual void Bind(int stage, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps);
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
class GRenderTargetPS3Impl : public GRenderTargetPS3
|
||
|
{
|
||
|
public:
|
||
|
GPtr<GTexturePS3Impl> pTexture, pStencilTexture;
|
||
|
GRendererPS3Impl* pRenderer;
|
||
|
CellGcmSurface Surf;
|
||
|
UInt ActualHeight;
|
||
|
bool Tiled;
|
||
|
UInt TargetWidth, TargetHeight;
|
||
|
bool IsTemp;
|
||
|
|
||
|
GRenderTargetPS3Impl(GRendererPS3Impl* prenderer);
|
||
|
~GRenderTargetPS3Impl();
|
||
|
|
||
|
virtual GRenderer* GetRenderer() const;
|
||
|
void RemoveFromRenderer();
|
||
|
|
||
|
virtual bool InitRenderTarget(GTexture* ptarget, GTexture* pdepth = 0, GTexture* pstencil = 0);
|
||
|
virtual bool InitRenderTarget(PS3RenderTargetParams params);
|
||
|
|
||
|
void SetRenderTarget(GRenderer::StereoDisplay disp);
|
||
|
};
|
||
|
|
||
|
// Vertex buffer structure used for glyphs.
|
||
|
struct GGlyphVertex
|
||
|
{
|
||
|
float x,y;
|
||
|
float u,v;
|
||
|
GColor color;
|
||
|
|
||
|
void SetVertex2D(float xx, float yy, float uu, float vv, GColor c)
|
||
|
{
|
||
|
x = xx; y = yy; u = uu; v = vv;
|
||
|
color = c;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class GBufferNode : public GRendererNode, public GNewOverrideBase<GStat_Default_Mem>
|
||
|
{
|
||
|
public:
|
||
|
GAllocatorPS3::Handle BufferH;
|
||
|
void* pData;
|
||
|
UInt32 offset;
|
||
|
GRenderer::CachedData* pcache;
|
||
|
|
||
|
GBufferNode() : GRendererNode()
|
||
|
{ BufferH = 0; pcache = 0; pData = 0; }
|
||
|
GBufferNode(GBufferNode *p, GRenderer::CachedData *d) : GRendererNode(p)
|
||
|
{ pData = 0; BufferH = 0; pcache = d; }
|
||
|
};
|
||
|
|
||
|
// ***** Renderer Implementation
|
||
|
|
||
|
#define M(x,r,c) x[(r)*4+(c)]
|
||
|
|
||
|
static void MakeOrtho(Float *O, Float left, Float right, Float top, Float bottom, Float near, Float far)
|
||
|
{
|
||
|
for (int i = 0; i < 16; i++)
|
||
|
O[i] = 0;
|
||
|
|
||
|
M(O, 0,0) = 2.0f / (right - left);
|
||
|
M(O, 1,1) = 2.0f / (top - bottom);
|
||
|
M(O, 2,2) = -2.0f / (far - near);
|
||
|
M(O, 3,3) = 1;
|
||
|
|
||
|
M(O, 0,3) = -(right + left) / (right - left);
|
||
|
M(O, 1,3) = -(top + bottom) / (top - bottom);
|
||
|
M(O, 2,3) = -(far + near) / (far - near);
|
||
|
}
|
||
|
|
||
|
#undef M
|
||
|
|
||
|
class GRendererPS3Impl : public GRendererPS3
|
||
|
{
|
||
|
public:
|
||
|
// Some renderer state.
|
||
|
GAllocatorPS3* Allocator;
|
||
|
CellGcmContextData* GcmCtx;
|
||
|
SInt32 MaxCmdSize;
|
||
|
bool ModeSet;
|
||
|
SInt RenderMode;
|
||
|
GMatrix3D BaseMatrix, CurMatrix;
|
||
|
|
||
|
// Output size.
|
||
|
Float DisplayWidth;
|
||
|
Float DisplayHeight;
|
||
|
|
||
|
GViewport ViewRect;
|
||
|
GRenderer::Matrix UserMatrix;
|
||
|
GRenderer::Matrix CurrentMatrix;
|
||
|
GRenderer::Cxform CurrentCxform;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
bool UVPMatricesChanged;
|
||
|
GMatrix3D ViewMatrix, ProjMatrix;
|
||
|
GMatrix3D UVPMatrix;
|
||
|
const GMatrix3D* pWorldMatrix;
|
||
|
#endif
|
||
|
|
||
|
// Link list of all allocated textures
|
||
|
GRendererNode Textures;
|
||
|
GRendererNode RenderTargets;
|
||
|
mutable GLock TexturesLock;
|
||
|
|
||
|
// Statistics
|
||
|
Stats RenderStats;
|
||
|
// Video memory
|
||
|
GMemoryStat TextureVMem;
|
||
|
GMemoryStat BufferVMem;
|
||
|
// Counts
|
||
|
GCounterStat TextureUploadCnt;
|
||
|
GCounterStat TextureUpdateCnt;
|
||
|
GCounterStat DPLineCnt;
|
||
|
GCounterStat DPTriangleCnt;
|
||
|
GCounterStat LineCnt;
|
||
|
GCounterStat TriangleCnt;
|
||
|
GCounterStat MaskCnt;
|
||
|
GCounterStat FilterCnt;
|
||
|
|
||
|
// Vertex data pointer
|
||
|
GBufferNode BufferObjects;
|
||
|
const void* pVertexData;
|
||
|
const void* pIndexData;
|
||
|
UInt32 IndexArray;
|
||
|
SInt VertexArray;
|
||
|
VertexFormat VertexFmt;
|
||
|
SInt IndexFmt;
|
||
|
|
||
|
// vertex array
|
||
|
Handle VA_memobj;
|
||
|
UByte* VA_base;
|
||
|
SInt VA_location;
|
||
|
UInt32 VA_offset, VA_size;
|
||
|
UInt32 VA_start, VA_end, VA_lastv, VA_count, VA_shift;
|
||
|
UInt VA_label;
|
||
|
|
||
|
// Stencil counter - for increment/decrement compares.
|
||
|
SInt StencilCounter;
|
||
|
bool StencilEnabled;
|
||
|
|
||
|
// Current sample mode
|
||
|
BitmapSampleMode SampleMode;
|
||
|
|
||
|
typedef GArrayConstPolicy<0, 4, true> NeverShrinkPolicy;
|
||
|
typedef GArrayLH<BlendType, GStat_Default_Mem, NeverShrinkPolicy> BlendModeStackType;
|
||
|
|
||
|
// Current blend mode
|
||
|
BlendType BlendMode;
|
||
|
BlendModeStackType BlendModeStack;
|
||
|
|
||
|
// render target
|
||
|
struct RTState
|
||
|
{
|
||
|
GRenderTargetPS3Impl* pRT;
|
||
|
GMatrix3D ViewMatrix;
|
||
|
GMatrix3D ViewMatrix3D;
|
||
|
GMatrix3D PerspMatrix3D;
|
||
|
const GMatrix3D* pWorldMatrix3D;
|
||
|
GViewport ViewRect;
|
||
|
SInt RenderMode;
|
||
|
SInt StencilCounter;
|
||
|
bool StencilEnabled;
|
||
|
|
||
|
RTState() { pRT = 0; pWorldMatrix3D = 0; }
|
||
|
RTState(GRenderTargetPS3Impl* prt, const GMatrix3D& vm,
|
||
|
const GMatrix3D& vm3d, const GMatrix3D &vp3d, const GMatrix3D* pw3d, const GViewport& vp, SInt rm, SInt sc, bool se)
|
||
|
: pRT(prt), ViewMatrix(vm), ViewMatrix3D(vm3d), PerspMatrix3D(vp3d), pWorldMatrix3D(pw3d), ViewRect(vp),
|
||
|
RenderMode(rm), StencilCounter(sc), StencilEnabled(se) { }
|
||
|
};
|
||
|
typedef GArrayLH<RTState, GStat_Default_Mem, NeverShrinkPolicy> RTStackType;
|
||
|
|
||
|
GRenderTargetPS3Impl* pCurRenderTarget;
|
||
|
RTStackType RenderTargetStack;
|
||
|
GArrayLH<GPtr<GRenderTargetPS3Impl> > TempRenderTargets;
|
||
|
GArrayLH<GPtr<GTexturePS3Impl> > TempStencilBuffers;
|
||
|
|
||
|
// Linked list used for buffer cache testing, otherwise holds no data.
|
||
|
CacheNode CacheList;
|
||
|
|
||
|
int CurrentShader;
|
||
|
int CurVProgram;
|
||
|
CgShader CgFShaders[PS_Count];
|
||
|
CgVProgram CgVShaders[3];
|
||
|
CgShader FilterShaders[FS2_Count];
|
||
|
|
||
|
UInt32 VMCFlags;
|
||
|
|
||
|
// ****
|
||
|
|
||
|
GRendererPS3Impl()
|
||
|
{
|
||
|
ModeSet = 1;
|
||
|
|
||
|
SampleMode = Sample_Linear;
|
||
|
RenderMode = 0;
|
||
|
pVertexData = 0;
|
||
|
pIndexData = 0;
|
||
|
VertexFmt = Vertex_None;
|
||
|
IndexFmt = 0;
|
||
|
|
||
|
StencilCounter = 0;
|
||
|
memset(CgFShaders, 0, sizeof(CgFShaders));
|
||
|
memset(FilterShaders, 0, sizeof(FilterShaders));
|
||
|
VA_size = 0;
|
||
|
VA_memobj = 0;
|
||
|
Allocator = 0;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
pWorldMatrix = 0;
|
||
|
S3DDisplay = StereoCenter;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
~GRendererPS3Impl()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
GAllocatorPS3* GetAllocator()
|
||
|
{
|
||
|
return Allocator;
|
||
|
}
|
||
|
|
||
|
void Clear()
|
||
|
{
|
||
|
// Remove/notify all textures
|
||
|
{
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
while (Textures.pFirst != &Textures)
|
||
|
((GTexturePS3Impl*)Textures.pFirst)->RemoveFromRenderer();
|
||
|
|
||
|
while (RenderTargets.pFirst != &RenderTargets)
|
||
|
((GRenderTargetPS3Impl*)RenderTargets.pFirst)->RemoveFromRenderer();
|
||
|
}
|
||
|
|
||
|
CacheList.ReleaseList();
|
||
|
|
||
|
for (GRendererNode *p = BufferObjects.pFirst; p; )
|
||
|
{
|
||
|
GBufferNode *pn = (GBufferNode*)p;
|
||
|
if (pn->BufferH)
|
||
|
Allocator->Free(pn->BufferH);
|
||
|
|
||
|
if (pn->pcache)
|
||
|
pn->pcache->ReleaseDataByRenderer();
|
||
|
p = p->pNext;
|
||
|
if (p == BufferObjects.pLast)
|
||
|
p->pNext = 0;
|
||
|
if (pn != &BufferObjects)
|
||
|
delete pn;
|
||
|
}
|
||
|
BufferObjects.pFirst = NULL;
|
||
|
|
||
|
Allocator->Free(VA_memobj);
|
||
|
VA_memobj = 0;
|
||
|
|
||
|
for (int i = 0; i < PS_Count; i++)
|
||
|
if (CgFShaders[i].memobj)
|
||
|
{
|
||
|
Allocator->Free(CgFShaders[i].memobj);
|
||
|
CgFShaders[i].memobj = 0;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < FS2_Count; i++)
|
||
|
if (FilterShaders[i].memobj)
|
||
|
{
|
||
|
Allocator->Free(FilterShaders[i].memobj);
|
||
|
FilterShaders[i].memobj = 0;
|
||
|
}
|
||
|
|
||
|
TempStencilBuffers.Clear();
|
||
|
TempRenderTargets.Clear();
|
||
|
}
|
||
|
|
||
|
void ReleaseResources()
|
||
|
{
|
||
|
Clear();
|
||
|
};
|
||
|
|
||
|
// Utility. Mutates *width, *height and *data to create the
|
||
|
// next mip level.
|
||
|
static void MakeNextMiplevel(UInt* width, UInt* height, UByte* data, int bpp)
|
||
|
{
|
||
|
GASSERT(width);
|
||
|
GASSERT(height);
|
||
|
GASSERT(data);
|
||
|
|
||
|
UInt newW = *width >> 1;
|
||
|
UInt newH = *height >> 1;
|
||
|
if (newW < 1) newW = 1;
|
||
|
if (newH < 1) newH = 1;
|
||
|
|
||
|
if (newW * 2 != *width || newH * 2 != *height)
|
||
|
{
|
||
|
// width or height was already 1, one dimensional resample
|
||
|
if (bpp == 1)
|
||
|
{
|
||
|
UByte* out = ((UByte*) data);
|
||
|
UByte* in = ((UByte*) data);
|
||
|
for (UInt i = 0; i < newW * newH; i++)
|
||
|
{
|
||
|
int a = (*(in + 0) + *(in + 1));
|
||
|
*(out) = UByte(a >> 1);
|
||
|
out++;
|
||
|
in += 2;
|
||
|
}
|
||
|
}
|
||
|
else if (bpp == 3)
|
||
|
{
|
||
|
UByte* out = ((UByte*) data);
|
||
|
UByte* in = ((UByte*) data);
|
||
|
for (UInt i = 0; i < newW * newH; i++)
|
||
|
{
|
||
|
int r,g,b;
|
||
|
r = ( *(in + 0) + *(in + 3));
|
||
|
g = ( *(in + 1) + *(in + 4));
|
||
|
b = ( *(in + 2) + *(in + 5));
|
||
|
out[0] = UByte(r >> 1);
|
||
|
out[1] = UByte(g >> 1);
|
||
|
out[2] = UByte(b >> 1);
|
||
|
out += 3;
|
||
|
in += 6;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UByte* out = ((UByte*) data);
|
||
|
UByte* in = ((UByte*) data);
|
||
|
for (UInt i = 0; i < newW * newH; i++)
|
||
|
{
|
||
|
int r,g,b,a;
|
||
|
r = ( *(in + 0) + *(in + 4));
|
||
|
g = ( *(in + 1) + *(in + 5));
|
||
|
b = ( *(in + 2) + *(in + 6));
|
||
|
a = ( *(in + 3) + *(in + 7));
|
||
|
out[0] = UByte(r >> 1);
|
||
|
out[1] = UByte(g >> 1);
|
||
|
out[2] = UByte(b >> 1);
|
||
|
out[3] = UByte(a >> 1);
|
||
|
out += 4;
|
||
|
in += 8;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (bpp == 1)
|
||
|
{
|
||
|
// Resample. Simple average 2x2 --> 1, in-place.
|
||
|
for (UInt j = 0; j < newH; j++)
|
||
|
{
|
||
|
UByte* out = ((UByte*) data) + j * newW;
|
||
|
UByte* in = ((UByte*) data) + (j << 1) * *width;
|
||
|
for (UInt i = 0; i < newW; i++)
|
||
|
{
|
||
|
int a = (*(in + 0) + *(in + 1) + *(in + 0 + *width) + *(in + 1 + *width));
|
||
|
*(out) = UByte(a >> 2);
|
||
|
out++;
|
||
|
in += 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (bpp == 3)
|
||
|
{
|
||
|
// Resample. Simple average 2x2 --> 1, in-place.
|
||
|
for (UInt j = 0; j < newH; j++)
|
||
|
{
|
||
|
UByte* out = ((UByte*) data) + j * (3 * newW);
|
||
|
UByte* in = ((UByte*) data) + (j << 1) * (3 * *width);
|
||
|
for (UInt i = 0; i < newW; i++)
|
||
|
{
|
||
|
int r,g,b;
|
||
|
r = ( *(in + 0) + *(in + 3) + *(in + 0 + (*width * 3)) + *(in + 3 + (*width * 3)) );
|
||
|
g = ( *(in + 1) + *(in + 4) + *(in + 1 + (*width * 3)) + *(in + 4 + (*width * 3)) );
|
||
|
b = ( *(in + 2) + *(in + 5) + *(in + 2 + (*width * 3)) + *(in + 5 + (*width * 3)) );
|
||
|
out[0] = UByte(r >> 2);
|
||
|
out[1] = UByte(g >> 2);
|
||
|
out[2] = UByte(b >> 2);
|
||
|
out += 3;
|
||
|
in += 6;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Resample. Simple average 2x2 --> 1, in-place.
|
||
|
for (UInt j = 0; j < newH; j++)
|
||
|
{
|
||
|
UByte* out = ((UByte*) data) + j * (4 * newW);
|
||
|
UByte* in = ((UByte*) data) + (j << 1) * (4 * *width);
|
||
|
for (UInt i = 0; i < newW; i++)
|
||
|
{
|
||
|
int r,g,b,a;
|
||
|
r = ( *(in + 0) + *(in + 4) + *(in + 0 + (*width * 4)) + *(in + 4 + (*width * 4)) );
|
||
|
g = ( *(in + 1) + *(in + 5) + *(in + 1 + (*width * 4)) + *(in + 5 + (*width * 4)) );
|
||
|
b = ( *(in + 2) + *(in + 6) + *(in + 2 + (*width * 4)) + *(in + 6 + (*width * 4)) );
|
||
|
a = ( *(in + 3) + *(in + 7) + *(in + 3 + (*width * 4)) + *(in + 7 + (*width * 4)) );
|
||
|
out[0] = UByte(r >> 2);
|
||
|
out[1] = UByte(g >> 2);
|
||
|
out[2] = UByte(b >> 2);
|
||
|
out[3] = UByte(a >> 2);
|
||
|
out += 4;
|
||
|
in += 8;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set parameters to reflect the new size
|
||
|
*width = newW;
|
||
|
*height = newH;
|
||
|
}
|
||
|
|
||
|
// Fill helper function:
|
||
|
// Applies fill texture by setting it to the specified stage, initializing samplers and vertex constants
|
||
|
void ApplyFillTexture(const FillTexture &fill, int stageIndex0)
|
||
|
{
|
||
|
GASSERT (fill.pTexture != 0);
|
||
|
if (fill.pTexture == 0) return; // avoid crash in release build
|
||
|
|
||
|
GTexturePS3Impl* ptexture = ((GTexturePS3Impl*)fill.pTexture);
|
||
|
ptexture->Bind(stageIndex0, fill.WrapMode, fill.SampleMode, 0);
|
||
|
SetTexgenState (stageIndex0, fill);
|
||
|
}
|
||
|
|
||
|
void ApplyPShaderCxform(const Cxform &cxform) const
|
||
|
{
|
||
|
Float scm[4] = { cxform.M_[0][0], cxform.M_[1][0],
|
||
|
cxform.M_[2][0], cxform.M_[3][0] };
|
||
|
Float sca[4] = { cxform.M_[0][1] / 255.0f, cxform.M_[1][1] / 255.0f,
|
||
|
cxform.M_[2][1] / 255.0f, cxform.M_[3][1] / 255.0f };
|
||
|
|
||
|
cellGcmSetFragmentProgramParameter (GcmCtx, CgFShaders[CurrentShader].prog, CgFShaders[CurrentShader].cxmul, scm,
|
||
|
CgFShaders[CurrentShader].offset);
|
||
|
cellGcmSetFragmentProgramParameter (GcmCtx, CgFShaders[CurrentShader].prog, CgFShaders[CurrentShader].cxadd, sca,
|
||
|
CgFShaders[CurrentShader].offset);
|
||
|
}
|
||
|
|
||
|
void SetTexgenState (SInt stageIndex, const FillTexture& fill)
|
||
|
{
|
||
|
const GRenderer::Matrix& m = fill.TextureMatrix;
|
||
|
Float p[4] = { 0, 0, 0, 0 };
|
||
|
|
||
|
GASSERT(stageIndex < 2);
|
||
|
p[0] = m.M_[0][0];
|
||
|
p[1] = m.M_[0][1];
|
||
|
p[3] = m.M_[0][2];
|
||
|
cellGcmSetVertexProgramParameter (GcmCtx, CgVShaders[CurVProgram].texgenx[stageIndex], p);
|
||
|
p[0] = m.M_[1][0];
|
||
|
p[1] = m.M_[1][1];
|
||
|
p[3] = m.M_[1][2];
|
||
|
cellGcmSetVertexProgramParameter (GcmCtx, CgVShaders[CurVProgram].texgeny[stageIndex], p);
|
||
|
}
|
||
|
|
||
|
void SetPixelShader (PixelShaderType ps)
|
||
|
{
|
||
|
CurrentShader = ps;
|
||
|
}
|
||
|
|
||
|
void TransferShaders()
|
||
|
{
|
||
|
cellGcmSetUpdateFragmentProgramParameter(GcmCtx, CgFShaders[CurrentShader].offset);
|
||
|
cellGcmSetFragmentProgram(GcmCtx, CgFShaders[CurrentShader].prog, CgFShaders[CurrentShader].offset);
|
||
|
cellGcmSetVertexProgram(GcmCtx, CgVShaders[CurVProgram].prog, CgVShaders[CurVProgram].uc);
|
||
|
}
|
||
|
|
||
|
bool SetVertexProgram (VertexFormat vf, SInt numtex)
|
||
|
{
|
||
|
switch (vf)
|
||
|
{
|
||
|
case Vertex_XY16iCF32:
|
||
|
case Vertex_XY16iC32:
|
||
|
CurVProgram = (numtex == 2) ? 1 : 0;
|
||
|
return 1;
|
||
|
|
||
|
default:
|
||
|
CurVProgram = numtex ? numtex-1 : 2;
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class GFxFillStyle
|
||
|
{
|
||
|
public:
|
||
|
enum FillMode
|
||
|
{
|
||
|
FM_None,
|
||
|
FM_Color,
|
||
|
FM_Bitmap,
|
||
|
FM_Gouraud
|
||
|
};
|
||
|
|
||
|
FillMode Mode;
|
||
|
GouraudFillType GouraudType;
|
||
|
GColor Color;
|
||
|
FillTexture Fill, Fill2;
|
||
|
|
||
|
GRenderer::Cxform BitmapColorTransform;
|
||
|
bool HasNonzeroAdditiveCxform;
|
||
|
|
||
|
GFxFillStyle()
|
||
|
{
|
||
|
Mode = FM_None;
|
||
|
HasNonzeroAdditiveCxform = false;
|
||
|
}
|
||
|
|
||
|
// Push our style into OpenGL.
|
||
|
void Apply(GRendererPS3Impl *prenderer) const
|
||
|
{
|
||
|
GASSERT(Mode != FM_None);
|
||
|
|
||
|
if (Mode == FM_Color)
|
||
|
{
|
||
|
prenderer->SetVertexProgram(prenderer->VertexFmt, 0);
|
||
|
prenderer->SetPixelShader(PS_Solid);
|
||
|
prenderer->ApplyColor(Color);
|
||
|
|
||
|
if ((Color.GetAlpha() == 0xFF) && (prenderer->BlendMode <= Blend_Normal))
|
||
|
cellGcmSetBlendEnable(prenderer->GcmCtx, CELL_GCM_FALSE);
|
||
|
else
|
||
|
cellGcmSetBlendEnable(prenderer->GcmCtx, CELL_GCM_TRUE);
|
||
|
}
|
||
|
else if (Mode == FM_Bitmap)
|
||
|
{
|
||
|
if (Fill.pTexture == NULL)
|
||
|
{
|
||
|
prenderer->SetVertexProgram(prenderer->VertexFmt, 0);
|
||
|
prenderer->SetPixelShader(PS_Solid);
|
||
|
prenderer->ApplyColor(Color);
|
||
|
|
||
|
if ((Color.GetAlpha() == 0xFF) && (prenderer->BlendMode <= Blend_Normal))
|
||
|
cellGcmSetBlendEnable(prenderer->GcmCtx, CELL_GCM_FALSE);
|
||
|
else
|
||
|
cellGcmSetBlendEnable(prenderer->GcmCtx, CELL_GCM_TRUE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
prenderer->SetVertexProgram(prenderer->VertexFmt, 1);
|
||
|
cellGcmSetBlendEnable(prenderer->GcmCtx, CELL_GCM_TRUE);
|
||
|
|
||
|
PixelShaderType shader = PS_CxformTexture;
|
||
|
|
||
|
//if (((GTexturePS3Impl*)Fill.pTexture)->IsYUVTexture())
|
||
|
// shader = PS_CxformTextureYUV;
|
||
|
|
||
|
if (prenderer->BlendMode == Blend_Multiply || prenderer->BlendMode == Blend_Darken)
|
||
|
shader = (PixelShaderType)(shader + (PS_CxformTextureMultiply - PS_CxformTexture));
|
||
|
|
||
|
prenderer->SetPixelShader(shader);
|
||
|
prenderer->ApplyFillTexture(Fill, 0);
|
||
|
prenderer->ApplyPShaderCxform(BitmapColorTransform);
|
||
|
}
|
||
|
}
|
||
|
else if (Mode == FM_Gouraud)
|
||
|
{
|
||
|
PixelShaderType shader = PS_None;
|
||
|
|
||
|
prenderer->SetVertexProgram(prenderer->VertexFmt,
|
||
|
GouraudType == GFill_2Texture || GouraudType == GFill_2TextureColor ? 2 : 1);
|
||
|
|
||
|
// No texture: generate color-shaded triangles.
|
||
|
if (Fill.pTexture == NULL)
|
||
|
{
|
||
|
cellGcmSetBlendEnable(prenderer->GcmCtx, CELL_GCM_TRUE);
|
||
|
|
||
|
if (prenderer->VertexFmt == Vertex_XY16iC32)
|
||
|
{
|
||
|
// Cxform Alpha Add can not be non-zero is this state because
|
||
|
// cxform blend equations can not work correctly.
|
||
|
// If we hit this assert, it means Vertex_XY16iCF32 should have been used.
|
||
|
//GASSERT (BitmapColorTransform.M_[3][1] < 1.0f);
|
||
|
|
||
|
shader = PS_CxformGouraudNoAddAlpha;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
shader = PS_CxformGouraud;
|
||
|
}
|
||
|
}
|
||
|
// We have a textured or multi-textured gouraud case.
|
||
|
else
|
||
|
{
|
||
|
cellGcmSetBlendEnable(prenderer->GcmCtx, CELL_GCM_TRUE);
|
||
|
|
||
|
if ((GouraudType == GFill_1TextureColor) ||
|
||
|
(GouraudType == GFill_1Texture))
|
||
|
shader = PS_CxformGouraudTexture;
|
||
|
else
|
||
|
shader = PS_Cxform2Texture;
|
||
|
}
|
||
|
|
||
|
if ((prenderer->BlendMode == Blend_Multiply) ||
|
||
|
(prenderer->BlendMode == Blend_Darken) )
|
||
|
{
|
||
|
shader = (PixelShaderType)(shader + (PS_CxformGouraudMultiply - PS_CxformGouraud));
|
||
|
|
||
|
// For indexing to work, these should hold:
|
||
|
GCOMPILER_ASSERT( (PS_Cxform2Texture - PS_CxformGouraud) ==
|
||
|
(PS_CxformMultiply2Texture - PS_CxformGouraudMultiply));
|
||
|
GCOMPILER_ASSERT( (PS_CxformGouraudMultiply - PS_CxformGouraud) ==
|
||
|
(PS_Cxform2Texture - PS_CxformGouraud + 1) );
|
||
|
}
|
||
|
prenderer->SetPixelShader(shader);
|
||
|
prenderer->ApplyPShaderCxform(BitmapColorTransform);
|
||
|
|
||
|
if (Fill.pTexture)
|
||
|
{
|
||
|
prenderer->ApplyFillTexture(Fill, 0);
|
||
|
prenderer->SetTexgenState (0, Fill);
|
||
|
|
||
|
if (Fill2.pTexture &&
|
||
|
(GouraudType == GFill_2TextureColor) ||
|
||
|
(GouraudType == GFill_2Texture))
|
||
|
{
|
||
|
prenderer->ApplyFillTexture(Fill2, 1);
|
||
|
prenderer->SetTexgenState (1, Fill2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Disable() { Mode = FM_None; Fill.pTexture = 0; }
|
||
|
|
||
|
void SetColor(GColor color) { Mode = FM_Color; Color = color; }
|
||
|
|
||
|
void SetCxform(const Cxform& colorTransform)
|
||
|
{
|
||
|
BitmapColorTransform = colorTransform;
|
||
|
|
||
|
if ( BitmapColorTransform.M_[0][1] > 1.0f ||
|
||
|
BitmapColorTransform.M_[1][1] > 1.0f ||
|
||
|
BitmapColorTransform.M_[2][1] > 1.0f ||
|
||
|
BitmapColorTransform.M_[3][1] > 1.0f )
|
||
|
HasNonzeroAdditiveCxform = true;
|
||
|
else
|
||
|
HasNonzeroAdditiveCxform = false;
|
||
|
}
|
||
|
|
||
|
void SetBitmap(const FillTexture* pft, const Cxform& colorTransform)
|
||
|
{
|
||
|
Mode = FM_Bitmap;
|
||
|
Fill = *pft;
|
||
|
Color = GColor(0xFFFFFFFF);
|
||
|
|
||
|
SetCxform(colorTransform);
|
||
|
}
|
||
|
|
||
|
// Sets the interpolated color/texture fill style used for shapes with EdgeAA.
|
||
|
// The specified textures are applied to vertices {0, 1, 2} of each triangle based
|
||
|
// on factors of Complex vertex. Any or all subsequent pointers can be NULL, in which case
|
||
|
// texture is not applied and vertex colors used instead.
|
||
|
void SetGouraudFill(GouraudFillType gfill,
|
||
|
const FillTexture *ptexture0,
|
||
|
const FillTexture *ptexture1,
|
||
|
const FillTexture *ptexture2, const Cxform& colorTransform)
|
||
|
{
|
||
|
|
||
|
// Texture2 is not yet used.
|
||
|
if (ptexture0 || ptexture1 || ptexture2)
|
||
|
{
|
||
|
const FillTexture *p = ptexture0;
|
||
|
if (!p) p = ptexture1;
|
||
|
|
||
|
SetBitmap(p, colorTransform);
|
||
|
// Used in 2 texture mode
|
||
|
if (ptexture1)
|
||
|
Fill2 = *ptexture1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetCxform(colorTransform);
|
||
|
Fill.pTexture = 0;
|
||
|
}
|
||
|
|
||
|
Mode = GFxFillStyle::FM_Gouraud;
|
||
|
GouraudType = gfill;
|
||
|
}
|
||
|
|
||
|
bool IsValid() const { return Mode != FM_None; }
|
||
|
};
|
||
|
|
||
|
|
||
|
// Style state.
|
||
|
enum StyleIndex
|
||
|
{
|
||
|
FILL_STYLE = 0,
|
||
|
LINE_STYLE,
|
||
|
STYLE_COUNT
|
||
|
};
|
||
|
GFxFillStyle CurrentStyles[STYLE_COUNT];
|
||
|
|
||
|
|
||
|
// Given an image, returns a Pointer to a GTexture struct
|
||
|
// that can later be passed to FillStyleX_bitmap(), to set a
|
||
|
// bitmap fill style.
|
||
|
GTexturePS3* CreateTexture()
|
||
|
{
|
||
|
GLock::Locker gruad(&TexturesLock);
|
||
|
return new GTexturePS3Impl(this);
|
||
|
}
|
||
|
|
||
|
GTexturePS3* CreateTextureYUV()
|
||
|
{
|
||
|
GLock::Locker gruad(&TexturesLock);
|
||
|
return new GTexturePS3ImplYUV(this);
|
||
|
}
|
||
|
|
||
|
GTexturePS3* CreateDepthStencilBuffer()
|
||
|
{
|
||
|
GLock::Locker gruad(&TexturesLock);
|
||
|
return new GTexturePS3Impl(this);
|
||
|
}
|
||
|
|
||
|
GRenderTargetPS3Impl* CreateRenderTarget()
|
||
|
{
|
||
|
return new GRenderTargetPS3Impl(this);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Helper function to query renderer capabilities.
|
||
|
bool GetRenderCaps(RenderCaps *pcaps)
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererPS3::GetRenderCaps fails - video mode not set");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
pcaps->CapBits = Cap_Index16 | Cap_Index32 | Cap_NestedMasks;
|
||
|
pcaps->BlendModes = (1<<Blend_None) | (1<<Blend_Normal) |
|
||
|
(1<<Blend_Multiply) | (1<<Blend_Lighten) | (1<<Blend_Darken) |
|
||
|
(1<<Blend_Add) | (1<<Blend_Subtract);
|
||
|
pcaps->VertexFormats= (1<<Vertex_None) | (1<<Vertex_XY16i) | (1<<Vertex_XY16iC32) | (1<<Vertex_XY16iCF32);
|
||
|
|
||
|
pcaps->CapBits |= Cap_CxformAdd | Cap_FillGouraud | Cap_FillGouraudTex |
|
||
|
Cap_TexNonPower2 | Cap_TexNonPower2Wrap | Cap_TexNonPower2Mip;
|
||
|
|
||
|
pcaps->CapBits |= Cap_RenderTargets | Cap_RenderTargetNonPow2;
|
||
|
pcaps->CapBits |= Cap_Filter_Blurs | Cap_Filter_ColorMatrix;
|
||
|
|
||
|
if (VMCFlags & VMConfig_FastTexUpdate)
|
||
|
pcaps->CapBits |= Cap_NoTexOverwrite;
|
||
|
|
||
|
pcaps->MaxTextureSize = 4096;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void SetDisplayRenderTarget(GRenderTarget* prt, bool setstate = 1)
|
||
|
{
|
||
|
GASSERT(RenderTargetStack.GetSize() == 0);
|
||
|
pCurRenderTarget = (GRenderTargetPS3Impl*)prt;
|
||
|
#ifndef GFC_NO_3D
|
||
|
if (setstate)
|
||
|
pCurRenderTarget->SetRenderTarget(S3DDisplay);
|
||
|
#else
|
||
|
if (setstate)
|
||
|
pCurRenderTarget->SetRenderTarget(GRenderer::StereoCenter);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void PushRenderTarget(const GRectF& FrameRect, GRenderTarget* prt)
|
||
|
{
|
||
|
RenderTargetStack.PushBack(RTState(pCurRenderTarget,BaseMatrix,
|
||
|
#ifndef GFC_NO_3D
|
||
|
ViewMatrix, ProjMatrix, pWorldMatrix,
|
||
|
#else
|
||
|
GMatrix3D(), GMatrix3D(), 0,
|
||
|
#endif
|
||
|
ViewRect,RenderMode,StencilCounter,StencilEnabled));
|
||
|
pCurRenderTarget = (GRenderTargetPS3Impl*)prt;
|
||
|
|
||
|
float dx = FrameRect.Width();
|
||
|
float dy = FrameRect.Height();
|
||
|
if (dx < 1) { dx = 1; }
|
||
|
if (dy < 1) { dy = 1; }
|
||
|
|
||
|
MakeOrtho(BaseMatrix, FrameRect.Left, FrameRect.Right, FrameRect.Top, FrameRect.Bottom, -1, 1);
|
||
|
ViewRect = GViewport(pCurRenderTarget->Surf.width, pCurRenderTarget->Surf.height,
|
||
|
0,0,pCurRenderTarget->TargetWidth, pCurRenderTarget->TargetHeight);
|
||
|
RenderMode = GViewport::View_RenderTextureAlpha;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
// set 3D view
|
||
|
GMatrix3D matView, matPersp;
|
||
|
MakeViewAndPersp3D(FrameRect, matView, matPersp, DEFAULT_FLASH_FOV);
|
||
|
SetView3D(matView);
|
||
|
SetPerspective3D(matPersp);
|
||
|
SetWorld3D(0);
|
||
|
#endif
|
||
|
|
||
|
pCurRenderTarget->SetRenderTarget(S3DDisplay);
|
||
|
float scale[4], offset[4];
|
||
|
scale[0] = ViewRect.Width * 0.5f;
|
||
|
scale[1] = -ViewRect.Height * 0.5f;
|
||
|
offset[0] = ViewRect.Left + ViewRect.Width * 0.5f;
|
||
|
offset[1] = ViewRect.Top + ViewRect.Height * 0.5f;
|
||
|
scale[2] = 0.5;
|
||
|
offset[2] = 0.5;
|
||
|
scale[3] = offset[3] = 0;
|
||
|
|
||
|
cellGcmSetViewport(GcmCtx, ViewRect.Left, ViewRect.Top, ViewRect.Width, ViewRect.Height, 0, 1, scale, offset);
|
||
|
if (ViewRect.Flags & GViewport::View_UseScissorRect)
|
||
|
cellGcmSetScissor(GcmCtx, ViewRect.ScissorLeft, ViewRect.BufferHeight-ViewRect.ScissorTop-ViewRect.ScissorHeight,
|
||
|
ViewRect.ScissorWidth, ViewRect.ScissorHeight);
|
||
|
else
|
||
|
cellGcmSetScissor(GcmCtx, 0,0, 4096,4096);
|
||
|
|
||
|
if (pCurRenderTarget->pTexture)
|
||
|
{
|
||
|
cellGcmSetClearColor(GcmCtx, 0);
|
||
|
cellGcmSetClearDepthStencil(GcmCtx, 0);
|
||
|
UInt32 clears = CELL_GCM_CLEAR_R|CELL_GCM_CLEAR_G|CELL_GCM_CLEAR_B|CELL_GCM_CLEAR_A;
|
||
|
if (pCurRenderTarget->pStencilTexture)
|
||
|
clears |= CELL_GCM_CLEAR_S|CELL_GCM_CLEAR_Z;
|
||
|
cellGcmSetClearSurface(GcmCtx, clears);
|
||
|
}
|
||
|
StencilEnabled = 0;
|
||
|
cellGcmSetStencilTestEnable(GcmCtx, CELL_GCM_FALSE);
|
||
|
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
|
||
|
void PopRenderTarget()
|
||
|
{
|
||
|
if (pCurRenderTarget->IsTemp)
|
||
|
pCurRenderTarget->pStencilTexture = 0;
|
||
|
|
||
|
RTState rts = RenderTargetStack.Back();
|
||
|
RenderTargetStack.PopBack();
|
||
|
pCurRenderTarget = rts.pRT;
|
||
|
BaseMatrix = rts.ViewMatrix;
|
||
|
ViewRect = rts.ViewRect;
|
||
|
RenderMode = rts.RenderMode;
|
||
|
StencilEnabled = rts.StencilEnabled;
|
||
|
StencilCounter = rts.StencilCounter;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
// restore 3D view matrix
|
||
|
SetView3D(rts.ViewMatrix3D);
|
||
|
SetPerspective3D(rts.PerspMatrix3D);
|
||
|
SetWorld3D(rts.pWorldMatrix3D);
|
||
|
#endif
|
||
|
|
||
|
pCurRenderTarget->SetRenderTarget(S3DDisplay);
|
||
|
float scale[4], offset[4];
|
||
|
scale[0] = ViewRect.Width * 0.5f;
|
||
|
scale[1] = ViewRect.Height * 0.5f;
|
||
|
offset[0] = ViewRect.Left + ViewRect.Width * 0.5f;
|
||
|
offset[1] = ViewRect.Top + ViewRect.Height * 0.5f;
|
||
|
scale[2] = 0.5;
|
||
|
offset[2] = 0.5;
|
||
|
scale[3] = offset[3] = 0;
|
||
|
|
||
|
if (!(ViewRect.Flags & GViewport::View_IsRenderTexture))
|
||
|
scale[1] = -scale[1];
|
||
|
|
||
|
cellGcmSetViewport(GcmCtx, ViewRect.Left, ViewRect.Top, ViewRect.Width, ViewRect.Height, 0, 1, scale, offset);
|
||
|
if (ViewRect.Flags & GViewport::View_UseScissorRect)
|
||
|
cellGcmSetScissor(GcmCtx, ViewRect.ScissorLeft, ViewRect.BufferHeight-ViewRect.ScissorTop-ViewRect.ScissorHeight,
|
||
|
ViewRect.ScissorWidth, ViewRect.ScissorHeight);
|
||
|
else
|
||
|
cellGcmSetScissor(GcmCtx, 0,0, 4096,4096);
|
||
|
|
||
|
cellGcmSetStencilTestEnable(GcmCtx, StencilEnabled ? CELL_GCM_TRUE : CELL_GCM_FALSE);
|
||
|
if (StencilEnabled)
|
||
|
{
|
||
|
cellGcmSetStencilFunc(GcmCtx, CELL_GCM_EQUAL, StencilCounter, 0xFF);
|
||
|
cellGcmSetStencilOp(GcmCtx, CELL_GCM_KEEP, CELL_GCM_KEEP, CELL_GCM_KEEP);
|
||
|
}
|
||
|
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
|
||
|
GTexturePS3Impl* PushTempRenderTarget(const GRectF& FrameRect, UInt inw, UInt inh, bool wantStencil = 0)
|
||
|
{
|
||
|
GRenderTargetPS3Impl* pRT = 0;
|
||
|
SInt w = 1, h = 1;
|
||
|
bool needsinit = false;
|
||
|
|
||
|
for (UInt i = 0; i < TempRenderTargets.GetSize(); i++)
|
||
|
if (TempRenderTargets[i]->pTexture->GetRefCount() <= 1 &&
|
||
|
TempRenderTargets[i]->pTexture->Tex.width >= SInt(inw) &&
|
||
|
TempRenderTargets[i]->pTexture->Tex.height >= SInt(inh))
|
||
|
{
|
||
|
pRT = TempRenderTargets[i];
|
||
|
goto dostencil;
|
||
|
}
|
||
|
|
||
|
while (w < SInt(inw)) w <<= 1;
|
||
|
while (h < SInt(inh)) h <<= 1;
|
||
|
|
||
|
for (UInt i = 0; i < TempRenderTargets.GetSize(); i++)
|
||
|
if (TempRenderTargets[i]->pTexture->GetRefCount() <= 1)
|
||
|
{
|
||
|
pRT = TempRenderTargets[i];
|
||
|
needsinit = true;
|
||
|
goto dostencil;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
GTexture* prtt = CreateTexture();
|
||
|
pRT = (GRenderTargetPS3Impl *)CreateRenderTarget();
|
||
|
pRT->IsTemp = true;
|
||
|
pRT->pTexture = (GTexturePS3Impl*) prtt; // will be properly initialized later
|
||
|
TempRenderTargets.PushBack(*pRT);
|
||
|
prtt->Release();
|
||
|
needsinit = true;
|
||
|
}
|
||
|
dostencil:
|
||
|
GTexturePS3Impl* pDepthStencil = 0;
|
||
|
|
||
|
if (w < pRT->pTexture->Tex.width)
|
||
|
w = pRT->pTexture->Tex.width;
|
||
|
if (h < pRT->pTexture->Tex.height)
|
||
|
h = pRT->pTexture->Tex.height;
|
||
|
|
||
|
GASSERT(!pRT->pStencilTexture);
|
||
|
if (wantStencil && (pRT->pStencilTexture.GetPtr() == 0 || pRT->pStencilTexture->GetRefCount() > 1))
|
||
|
{
|
||
|
for (UInt i = 0; i < TempStencilBuffers.GetSize(); i++)
|
||
|
{
|
||
|
if (TempStencilBuffers[i]->GetRefCount() <= 1 &&
|
||
|
TempStencilBuffers[i]->Tex.width >= SInt(inw) &&
|
||
|
TempStencilBuffers[i]->Tex.height >= SInt(inh))
|
||
|
{
|
||
|
pDepthStencil = TempStencilBuffers[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!pDepthStencil)
|
||
|
{
|
||
|
for (UInt i = 0; i < TempStencilBuffers.GetSize(); i++)
|
||
|
if (TempStencilBuffers[i]->GetRefCount() <= 1)
|
||
|
{
|
||
|
pDepthStencil = TempStencilBuffers[i];
|
||
|
pDepthStencil->InitDynamicTexture(w, h, GImage::Image_DepthStencil, 0, GTexture::Usage_RenderTarget);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!pDepthStencil)
|
||
|
{
|
||
|
pDepthStencil = (GTexturePS3Impl*) CreateDepthStencilBuffer();
|
||
|
pDepthStencil->InitDynamicTexture(w, h, GImage::Image_DepthStencil, 0, GTexture::Usage_RenderTarget);
|
||
|
TempStencilBuffers.PushBack(*pDepthStencil);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
needsinit = 1;
|
||
|
}
|
||
|
|
||
|
if (needsinit)
|
||
|
{
|
||
|
if (w != pRT->pTexture->Tex.width || h != pRT->pTexture->Tex.height)
|
||
|
pRT->pTexture->InitDynamicTexture(w, h, GImage::Image_ARGB_8888, 0, GTexture::Usage_RenderTarget);
|
||
|
|
||
|
// should use handlers instead
|
||
|
pRT->InitRenderTarget(pRT->pTexture, pDepthStencil, pDepthStencil);
|
||
|
}
|
||
|
|
||
|
pRT->TargetWidth = inw;
|
||
|
pRT->TargetHeight = inh;
|
||
|
PushRenderTarget(FrameRect, pRT);
|
||
|
return pRT->pTexture;
|
||
|
|
||
|
}
|
||
|
|
||
|
void ReleaseTempRenderTargets(UInt keepArea)
|
||
|
{
|
||
|
GArray<GPtr<GRenderTargetPS3Impl> > NewTempRenderTargets;
|
||
|
GArray<GPtr<GTexturePS3Impl> > NewTempStencilBuffers;
|
||
|
UInt stencilArea = keepArea;
|
||
|
|
||
|
for (UInt i = 0; i < TempRenderTargets.GetSize(); i++)
|
||
|
if (TempRenderTargets[i]->pTexture->GetRefCount() > 1 ||
|
||
|
UInt(TempRenderTargets[i]->pTexture->Tex.width * TempRenderTargets[i]->pTexture->Tex.height) <= keepArea)
|
||
|
{
|
||
|
NewTempRenderTargets.PushBack(TempRenderTargets[i]);
|
||
|
keepArea -= TempRenderTargets[i]->pTexture->Tex.width * TempRenderTargets[i]->pTexture->Tex.height;
|
||
|
}
|
||
|
|
||
|
TempRenderTargets.Clear();
|
||
|
TempRenderTargets.Append(NewTempRenderTargets.GetDataPtr(), NewTempRenderTargets.GetSize());
|
||
|
|
||
|
for (UInt i = 0; i < TempStencilBuffers.GetSize(); i++)
|
||
|
if (TempStencilBuffers[i]->GetRefCount() > 1 ||
|
||
|
UInt(TempStencilBuffers[i]->Tex.width * TempStencilBuffers[i]->Tex.height) <= stencilArea)
|
||
|
{
|
||
|
NewTempStencilBuffers.PushBack(TempStencilBuffers[i]);
|
||
|
stencilArea -= TempStencilBuffers[i]->Tex.width * TempStencilBuffers[i]->Tex.height;
|
||
|
}
|
||
|
|
||
|
TempStencilBuffers.Clear();
|
||
|
TempStencilBuffers.Append(NewTempStencilBuffers.GetDataPtr(), NewTempStencilBuffers.GetSize());
|
||
|
}
|
||
|
|
||
|
void DrawColorMatrixRect(GTexture* psrcin, const GRectF& insrcrect, const GRectF& destrect, const Float *matrix, bool islast)
|
||
|
{
|
||
|
GUNUSED(islast);
|
||
|
GTexturePS3Impl* psrc = (GTexturePS3Impl*) psrcin;
|
||
|
CgShader* pShader = &FilterShaders[(BlendMode == Blend_Multiply || BlendMode == Blend_Darken) ? FS2_FCMatrixMul : FS2_FCMatrix];
|
||
|
|
||
|
GRectF srcrect = GRectF(insrcrect.Left * 1.0f/psrc->Tex.width, insrcrect.Top * 1.0f/psrc->Tex.height,
|
||
|
insrcrect.Right * 1.0f/psrc->Tex.width, insrcrect.Bottom * 1.0f/psrc->Tex.height);
|
||
|
|
||
|
SetVertexProgram(Vertex_None, 0);
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
cellGcmSetVertexProgramParameter(GcmCtx, CgVShaders[CurVProgram].mvp, CurMatrix);
|
||
|
cellGcmSetFragmentProgramParameter (GcmCtx, pShader->prog, pShader->uniforms[FSU_cxmul], matrix, pShader->offset);
|
||
|
cellGcmSetFragmentProgramParameter (GcmCtx, pShader->prog, pShader->uniforms[FSU_cxadd], matrix+16, pShader->offset);
|
||
|
|
||
|
ApplyBlendMode(BlendMode, true, true);
|
||
|
|
||
|
psrc->Bind(-1, Wrap_Clamp, Sample_Linear, 0);
|
||
|
|
||
|
cellGcmSetUpdateFragmentProgramParameter(GcmCtx, pShader->offset);
|
||
|
cellGcmSetFragmentProgram(GcmCtx, pShader->prog, pShader->offset);
|
||
|
cellGcmSetVertexProgram(GcmCtx, CgVShaders[CurVProgram].prog, CgVShaders[CurVProgram].uc);
|
||
|
|
||
|
Float vertices[] = {destrect.Left, destrect.Top, srcrect.Left, srcrect.Top,
|
||
|
destrect.Right, destrect.Top, srcrect.Right, srcrect.Top,
|
||
|
destrect.Right, destrect.Bottom, srcrect.Right, srcrect.Bottom,
|
||
|
destrect.Left, destrect.Bottom, srcrect.Left, srcrect.Bottom};
|
||
|
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 16, 2, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].tci, 8, 16, 2, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetInvalidateVertexCache(GcmCtx);
|
||
|
cellGcmSetDrawInlineArray(GcmCtx, CELL_GCM_PRIMITIVE_QUADS, 16, vertices);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].tci, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
|
||
|
UInt CheckFilterSupport(const BlurFilterParams& params)
|
||
|
{
|
||
|
UInt flags = FilterSupport_Ok;
|
||
|
if (params.Passes > 1 || (params.BlurX * params.BlurY > 32))
|
||
|
flags |= FilterSupport_Multipass;
|
||
|
|
||
|
return flags;
|
||
|
}
|
||
|
|
||
|
inline void SetUniform(FragShaderType2 shader, FragShader2Uniform var, const Float *val, UInt size)
|
||
|
{
|
||
|
GUNUSED(size);
|
||
|
cellGcmSetFragmentProgramParameter (GcmCtx, FilterShaders[shader].prog, FilterShaders[shader].uniforms[var], val,
|
||
|
FilterShaders[shader].offset);
|
||
|
}
|
||
|
|
||
|
inline void SetUniform(FragShaderType2 shader, FragShader2Uniform var, Float x, Float y=0, Float z=0, Float w=1)
|
||
|
{
|
||
|
const Float val[] = {x,y,z,w};
|
||
|
cellGcmSetFragmentProgramParameter (GcmCtx, FilterShaders[shader].prog, FilterShaders[shader].uniforms[var], val,
|
||
|
FilterShaders[shader].offset);
|
||
|
}
|
||
|
|
||
|
void DrawBlurRect(GTexture* psrcin, const GRectF& insrcrect, const GRectF& indestrect, const BlurFilterParams& params, bool islast)
|
||
|
{
|
||
|
GUNUSED(islast);
|
||
|
GPtr<GTexturePS3Impl> psrcinRef = (GTexturePS3Impl*)psrcin;
|
||
|
GPtr<GTexturePS3Impl> psrc = (GTexturePS3Impl*)psrcin;
|
||
|
GRectF srcrect, destrect(-1,-1,1,1);
|
||
|
|
||
|
UInt n = params.Passes;
|
||
|
|
||
|
BlurFilterParams pass[3];
|
||
|
FragShaderType2 passis[3];
|
||
|
|
||
|
pass[0] = params;
|
||
|
pass[1] = params;
|
||
|
pass[2] = params;
|
||
|
|
||
|
bool mul = (BlendMode == Blend_Multiply || BlendMode == Blend_Darken);
|
||
|
passis[0] = passis[1] = FS2_FBox2Blur;
|
||
|
passis[2] = mul ? FS2_FBox2BlurMul : FS2_FBox2Blur;
|
||
|
|
||
|
if (params.Mode & Filter_Shadow)
|
||
|
{
|
||
|
if (params.Mode & Filter_HideObject)
|
||
|
{
|
||
|
passis[2] = FS2_FBox2Shadowonly;
|
||
|
|
||
|
if (params.Mode & Filter_Highlight)
|
||
|
passis[2] = (FragShaderType2) (passis[2] + FS2_shadows_Highlight);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params.Mode & Filter_Inner)
|
||
|
passis[2] = FS2_FBox2InnerShadow;
|
||
|
else
|
||
|
passis[2] = FS2_FBox2Shadow;
|
||
|
|
||
|
if (params.Mode & Filter_Knockout)
|
||
|
passis[2] = (FragShaderType2) (passis[2] + FS2_shadows_Knockout);
|
||
|
|
||
|
if (params.Mode & Filter_Highlight)
|
||
|
passis[2] = (FragShaderType2) (passis[2] + FS2_shadows_Highlight);
|
||
|
}
|
||
|
|
||
|
if (mul)
|
||
|
passis[2] = (FragShaderType2) (passis[2] + FS2_shadows_Mul);
|
||
|
}
|
||
|
|
||
|
if (params.BlurX * params.BlurY > 32)
|
||
|
{
|
||
|
n *= 2;
|
||
|
pass[0].BlurY = 1;
|
||
|
pass[1].BlurX = 1;
|
||
|
pass[2].BlurX = 1;
|
||
|
|
||
|
passis[0] = passis[1] = FS2_FBox1Blur;
|
||
|
if (passis[2] == FS2_FBox2Blur)
|
||
|
passis[2] = FS2_FBox1Blur;
|
||
|
else if (passis[2] == FS2_FBox2BlurMul)
|
||
|
passis[2] = FS2_FBox1BlurMul;
|
||
|
}
|
||
|
|
||
|
UInt bufWidth = (UInt)ceilf(insrcrect.Width());
|
||
|
UInt bufHeight = (UInt)ceilf(insrcrect.Height());
|
||
|
UInt last = n-1;
|
||
|
|
||
|
SetVertexProgram(Vertex_None, 0);
|
||
|
|
||
|
for (UInt i = 0; i < n; i++)
|
||
|
{
|
||
|
UInt passi = (i == n-1) ? 2 : (i&1);
|
||
|
const CgShader *pShader = &FilterShaders[passis[passi]];
|
||
|
const BlurFilterParams& pparams = pass[passi];
|
||
|
|
||
|
GTexturePS3Impl* pnextsrc;
|
||
|
if (i != n - 1)
|
||
|
{
|
||
|
pnextsrc = PushTempRenderTarget(GRectF(-1,-1,1,1), bufWidth, bufHeight);
|
||
|
ApplyMatrix(GMatrix2D::Identity);
|
||
|
destrect = GRectF(-1,-1,1,1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pnextsrc = 0;
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
destrect = indestrect;
|
||
|
}
|
||
|
|
||
|
srcrect = GRectF(insrcrect.Left * 1.0f/psrc->Tex.width, insrcrect.Top * 1.0f/psrc->Tex.height,
|
||
|
insrcrect.Right * 1.0f/psrc->Tex.width, insrcrect.Bottom * 1.0f/psrc->Tex.height);
|
||
|
|
||
|
cellGcmSetVertexProgramParameter(GcmCtx, CgVShaders[CurVProgram].mvp, CurMatrix);
|
||
|
|
||
|
if (i < last)
|
||
|
{
|
||
|
cellGcmSetBlendFunc(GcmCtx, CELL_GCM_ONE, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE, CELL_GCM_ONE_MINUS_SRC_ALPHA);
|
||
|
cellGcmSetBlendEquation(GcmCtx, CELL_GCM_FUNC_ADD, CELL_GCM_FUNC_ADD);
|
||
|
cellGcmSetBlendEnable(GcmCtx, CELL_GCM_TRUE);
|
||
|
}
|
||
|
else
|
||
|
ApplyBlendMode(BlendMode, true, true);
|
||
|
|
||
|
const float mult = 1.0f / 255.0f;
|
||
|
|
||
|
if (pShader->uniforms[FSU_cxadd] >= 0)
|
||
|
{
|
||
|
if (i == n - 1)
|
||
|
{
|
||
|
float cxformData[4 * 2] =
|
||
|
{
|
||
|
params.cxform.M_[0][0] * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[1][0] * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[2][0] * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[3][0],
|
||
|
|
||
|
params.cxform.M_[0][1] * mult * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[1][1] * mult * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[2][1] * mult * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[3][1] * mult
|
||
|
};
|
||
|
|
||
|
SetUniform(passis[passi], FSU_cxmul, cxformData, 4);
|
||
|
SetUniform(passis[passi], FSU_cxadd, cxformData+4, 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const float add[] = {0,0,0,0};
|
||
|
const float mul[] = {1,1,1,1};
|
||
|
SetUniform(passis[passi], FSU_cxmul, mul, 4);
|
||
|
SetUniform(passis[passi], FSU_cxadd, add, 4);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Float SizeX = UInt(pparams.BlurX-1) * 0.5f;
|
||
|
Float SizeY = UInt(pparams.BlurY-1) * 0.5f;
|
||
|
|
||
|
if (passis[passi] == FS2_FBox1Blur || passis[passi] == FS2_FBox1BlurMul)
|
||
|
{
|
||
|
const float fsize[] = {pparams.BlurX > 1 ? SizeX : SizeY, 0, 0, 1.0f/((SizeX*2+1)*(SizeY*2+1))};
|
||
|
SetUniform(passis[passi], FSU_fsize, fsize, 4);
|
||
|
|
||
|
SetUniform(passis[passi], FSU_texscale, pparams.BlurX > 1 ? 1.0f/psrc->Tex.width : 0, pparams.BlurY > 1 ? 1.0f/psrc->Tex.height : 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const float fsize[] = {SizeX, SizeY, 0, 1.0f/((SizeX*2+1)*(SizeY*2+1))};
|
||
|
SetUniform(passis[passi], FSU_fsize, fsize, 4);
|
||
|
SetUniform(passis[passi], FSU_texscale, 1.0f/psrc->Tex.width, 1.0f/psrc->Tex.height);
|
||
|
}
|
||
|
|
||
|
if (pShader->uniforms[FSU_offset])
|
||
|
{
|
||
|
SetUniform(passis[passi], FSU_offset, -params.Offset.x, -params.Offset.y);
|
||
|
if (pShader->uniforms[FSU_srctexscale])
|
||
|
SetUniform(passis[passi], FSU_srctexscale, psrc->Tex.width/Float(psrcinRef->Tex.width), psrc->Tex.height/Float(psrcinRef->Tex.height));
|
||
|
}
|
||
|
|
||
|
if (pShader->uniforms[FSU_scolor])
|
||
|
{
|
||
|
SetUniform(passis[passi], FSU_scolor,
|
||
|
params.Color.GetRed() * mult, params.Color.GetGreen() * mult, params.Color.GetBlue() * mult, params.Color.GetAlpha() * mult);
|
||
|
|
||
|
if (pShader->uniforms[FSU_scolor2])
|
||
|
SetUniform(passis[passi], FSU_scolor2,
|
||
|
params.Color2.GetRed() * mult, params.Color2.GetGreen() * mult, params.Color2.GetBlue() * mult, params.Color2.GetAlpha() * mult);
|
||
|
}
|
||
|
|
||
|
psrc->Bind(-pShader->texi[0]-1, Wrap_Clamp, Sample_Linear, 0);
|
||
|
if (pShader->tex[1])
|
||
|
((GTexturePS3Impl*)psrcin)->Bind(-pShader->texi[1]-1, Wrap_Clamp, Sample_Linear, 0);
|
||
|
|
||
|
cellGcmSetUpdateFragmentProgramParameter(GcmCtx, FilterShaders[passis[passi]].offset);
|
||
|
cellGcmSetFragmentProgram(GcmCtx, FilterShaders[passis[passi]].prog, FilterShaders[passis[passi]].offset);
|
||
|
cellGcmSetVertexProgram(GcmCtx, CgVShaders[CurVProgram].prog, CgVShaders[CurVProgram].uc);
|
||
|
|
||
|
Float vertices[] = {destrect.Left, destrect.Top, srcrect.Left, srcrect.Top,
|
||
|
destrect.Right, destrect.Top, srcrect.Right, srcrect.Top,
|
||
|
destrect.Right, destrect.Bottom, srcrect.Right, srcrect.Bottom,
|
||
|
destrect.Left, destrect.Bottom, srcrect.Left, srcrect.Bottom};
|
||
|
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 16, 2, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].tci, 8, 16, 2, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetInvalidateVertexCache(GcmCtx);
|
||
|
cellGcmSetDrawInlineArray(GcmCtx, CELL_GCM_PRIMITIVE_QUADS, 16, vertices);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].tci, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
|
||
|
if (i != n - 1)
|
||
|
{
|
||
|
PopRenderTarget();
|
||
|
psrc = pnextsrc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
FilterCnt.AddCount(n);
|
||
|
RenderStats.Filters += n;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set up to render a full frame from a movie and fills the
|
||
|
// background. Sets up necessary transforms, to scale the
|
||
|
// movie to fit within the given dimensions. Call
|
||
|
// EndDisplay() when you're done.
|
||
|
//
|
||
|
// The Rectangle (viewportX0, viewportY0,
|
||
|
// viewportX0 + viewportWidth, viewportY0 + viewportHeight)
|
||
|
// defines the window coordinates taken up by the movie.
|
||
|
//
|
||
|
// The Rectangle (x0, y0, x1, y1) defines the pixel
|
||
|
// coordinates of the movie that correspond to the viewport bounds.
|
||
|
void BeginDisplay(
|
||
|
GColor backgroundColor, const GViewport &viewport,
|
||
|
Float x0, Float x1, Float y0, Float y1)
|
||
|
|
||
|
{
|
||
|
GFC_DEBUG_ERROR(!pCurRenderTarget, "No render target set");
|
||
|
|
||
|
VA_base = (UByte*) Allocator->Map(VA_memobj);
|
||
|
VA_location = Allocator->GetLocation(VA_memobj);
|
||
|
VA_offset = Allocator->GetOffset(VA_memobj);
|
||
|
|
||
|
RenderMode = (viewport.Flags & GViewport::View_AlphaComposite);
|
||
|
|
||
|
DisplayWidth = fabsf(x1 - x0);
|
||
|
DisplayHeight = fabsf(y1 - y0);
|
||
|
|
||
|
float scale[4], offset[4];
|
||
|
scale[0] = viewport.Width * 0.5f;
|
||
|
scale[1] = viewport.Height * 0.5f;
|
||
|
offset[0] = viewport.Left + viewport.Width * 0.5f;
|
||
|
offset[1] = viewport.Top + viewport.Height * 0.5f;
|
||
|
scale[2] = 0.5;
|
||
|
offset[2] = 0.5;
|
||
|
scale[3] = offset[3] = 0;
|
||
|
|
||
|
if (!(viewport.Flags & GViewport::View_IsRenderTexture))
|
||
|
scale[1] = -scale[1];
|
||
|
|
||
|
cellGcmSetViewport(GcmCtx, viewport.Left, viewport.Top, viewport.Width, viewport.Height, 0, 1, scale, offset);
|
||
|
ViewRect = viewport;
|
||
|
|
||
|
if (viewport.Flags & GViewport::View_UseScissorRect)
|
||
|
cellGcmSetScissor(GcmCtx, viewport.ScissorLeft, viewport.BufferHeight-viewport.ScissorTop-viewport.ScissorHeight,
|
||
|
viewport.ScissorWidth, viewport.ScissorHeight);
|
||
|
else
|
||
|
cellGcmSetScissor(GcmCtx, 0,0, 4096,4096);
|
||
|
|
||
|
MakeOrtho(BaseMatrix, x0, x1, y0, y1, -1, 1);
|
||
|
memcpy(CurMatrix, BaseMatrix, sizeof(Float) * 16);
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
pWorldMatrix = 0;
|
||
|
#endif
|
||
|
|
||
|
cellGcmSetCullFaceEnable(GcmCtx, CELL_GCM_FALSE);
|
||
|
cellGcmSetZMinMaxControl(GcmCtx, CELL_GCM_TRUE, CELL_GCM_FALSE, CELL_GCM_FALSE);
|
||
|
|
||
|
cellGcmSetDepthTestEnable(GcmCtx, CELL_GCM_FALSE);
|
||
|
cellGcmSetStencilTestEnable(GcmCtx, CELL_GCM_FALSE);
|
||
|
cellGcmSetAlphaTestEnable(GcmCtx, CELL_GCM_FALSE);
|
||
|
|
||
|
cellGcmSetBlendEquation(GcmCtx, CELL_GCM_FUNC_ADD, CELL_GCM_FUNC_ADD);
|
||
|
cellGcmSetBlendFunc(GcmCtx,
|
||
|
CELL_GCM_SRC_ALPHA,
|
||
|
CELL_GCM_ONE_MINUS_SRC_ALPHA,
|
||
|
CELL_GCM_SRC_ALPHA,
|
||
|
CELL_GCM_ONE_MINUS_SRC_ALPHA);
|
||
|
|
||
|
for (int i = 0; i < 16; i++)
|
||
|
{
|
||
|
cellGcmSetVertexDataArray(GcmCtx, i, 0,0,0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
}
|
||
|
|
||
|
// Sample Mode
|
||
|
SampleMode = Sample_Linear;
|
||
|
|
||
|
BlendMode = Blend_Normal;
|
||
|
|
||
|
// Stencil counter starts out at 0.
|
||
|
StencilCounter = 0;
|
||
|
StencilEnabled = 0;
|
||
|
|
||
|
// Clear the background, if background color has alpha > 0.
|
||
|
if (backgroundColor.GetAlpha() > 0)
|
||
|
{
|
||
|
// Draw a big quad.
|
||
|
if (backgroundColor.GetAlpha() == 0xFF)
|
||
|
cellGcmSetBlendEnable(GcmCtx, CELL_GCM_FALSE);
|
||
|
else
|
||
|
cellGcmSetBlendEnable(GcmCtx, CELL_GCM_TRUE);
|
||
|
|
||
|
SetVertexProgram(Vertex_None, 0);
|
||
|
CurrentShader = PS_Solid;
|
||
|
ApplyColor(backgroundColor);
|
||
|
|
||
|
cellGcmSetVertexProgramParameter(GcmCtx, CgVShaders[CurVProgram].mvp, BaseMatrix);
|
||
|
TransferShaders();
|
||
|
|
||
|
Float bgVertBuffer[8];
|
||
|
bgVertBuffer[0] = x0; bgVertBuffer[1] = y0;
|
||
|
bgVertBuffer[2] = x1; bgVertBuffer[3] = y0;
|
||
|
bgVertBuffer[4] = x1; bgVertBuffer[5] = y1;
|
||
|
bgVertBuffer[6] = x0; bgVertBuffer[7] = y1;
|
||
|
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, sizeof(Float)*2, 2, CELL_GCM_VERTEX_F,
|
||
|
CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetInvalidateVertexCache(GcmCtx);
|
||
|
cellGcmSetDrawInlineArray(GcmCtx, CELL_GCM_PRIMITIVE_QUADS, 8, bgVertBuffer);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
}
|
||
|
|
||
|
cellGcmSetBlendEnable(GcmCtx, CELL_GCM_TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Clean up after rendering a frame. Client program is still
|
||
|
// responsible for calling glSwapBuffers() or whatever.
|
||
|
void EndDisplay()
|
||
|
{
|
||
|
Allocator->Unmap(VA_memobj, VA_base);
|
||
|
VA_base = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set the current transform for mesh & line-strip rendering.
|
||
|
void SetMatrix(const GRenderer::Matrix& m)
|
||
|
{
|
||
|
CurrentMatrix = m;
|
||
|
}
|
||
|
|
||
|
void SetUserMatrix(const GRenderer::Matrix& m)
|
||
|
{
|
||
|
UserMatrix = m;
|
||
|
#ifndef GFC_NO_3D
|
||
|
UVPMatricesChanged = 1;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Set the current color transform for mesh & line-strip rendering.
|
||
|
void SetCxform(const GRenderer::Cxform& cx)
|
||
|
{
|
||
|
CurrentCxform = cx;
|
||
|
}
|
||
|
|
||
|
struct BlendModeDesc
|
||
|
{
|
||
|
UInt32 op, src, dest;
|
||
|
};
|
||
|
|
||
|
struct BlendModeDescAlpha
|
||
|
{
|
||
|
UInt32 op, srcc, srca, destc, desta;
|
||
|
};
|
||
|
|
||
|
void ApplyBlendMode(BlendType mode, bool forceAc = 0, bool sourceAc = 0)
|
||
|
{
|
||
|
static BlendModeDesc modes[15] =
|
||
|
{
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // None
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Normal
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Layer
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_DST_COLOR, CELL_GCM_ZERO }, // Multiply
|
||
|
// (For multiply, should src be pre-multiplied by its inverse alpha?)
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Screen *??
|
||
|
|
||
|
{ CELL_GCM_MAX, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE }, // Lighten
|
||
|
{ CELL_GCM_MIN, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE }, // Darken
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Difference *??
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE }, // Add
|
||
|
{ CELL_GCM_FUNC_REVERSE_SUBTRACT, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE }, // Subtract
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Invert *??
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Alpha *??
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Erase *??
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Overlay *??
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // HardLight *??
|
||
|
};
|
||
|
|
||
|
// Blending into alpha textures with premultiplied colors
|
||
|
static BlendModeDescAlpha acmodes[30] =
|
||
|
{
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // None
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Normal
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Layer
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_DST_COLOR, CELL_GCM_DST_ALPHA, CELL_GCM_SRC_ALPHA, CELL_GCM_ZERO }, // Multiply
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Screen *??
|
||
|
|
||
|
{ CELL_GCM_MAX, CELL_GCM_SRC_ALPHA, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE, CELL_GCM_ONE }, // Lighten *??
|
||
|
{ CELL_GCM_MIN, CELL_GCM_SRC_ALPHA, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE, CELL_GCM_ONE }, // Darken *??
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Difference
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ZERO, CELL_GCM_ONE, CELL_GCM_ONE }, // Add
|
||
|
{ CELL_GCM_FUNC_REVERSE_SUBTRACT, CELL_GCM_SRC_ALPHA, CELL_GCM_ZERO, CELL_GCM_ONE, CELL_GCM_ONE }, // Subtract
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Invert *??
|
||
|
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Alpha *??
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Erase *??
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // Overlay *??
|
||
|
{ CELL_GCM_FUNC_ADD, CELL_GCM_SRC_ALPHA, CELL_GCM_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA, CELL_GCM_ONE_MINUS_SRC_ALPHA }, // HardLight *??
|
||
|
};
|
||
|
|
||
|
// For debug build
|
||
|
GASSERT(((UInt) mode) < 15);
|
||
|
// For release
|
||
|
if (((UInt) mode) >= 15)
|
||
|
mode = Blend_None;
|
||
|
|
||
|
if ((RenderMode & GViewport::View_AlphaComposite) || forceAc)
|
||
|
{
|
||
|
if (sourceAc && acmodes[mode].srcc == CELL_GCM_SRC_ALPHA)
|
||
|
cellGcmSetBlendFunc(GcmCtx, CELL_GCM_ONE, acmodes[mode].destc, acmodes[mode].srca, acmodes[mode].desta);
|
||
|
else
|
||
|
cellGcmSetBlendFunc(GcmCtx, acmodes[mode].srcc, acmodes[mode].destc, acmodes[mode].srca, acmodes[mode].desta);
|
||
|
cellGcmSetBlendEquation(GcmCtx, acmodes[mode].op, acmodes[mode].op);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sourceAc && modes[mode].src == CELL_GCM_SRC_ALPHA)
|
||
|
cellGcmSetBlendFunc(GcmCtx, CELL_GCM_ONE, modes[mode].dest, modes[mode].src, modes[mode].dest);
|
||
|
else
|
||
|
cellGcmSetBlendFunc(GcmCtx, modes[mode].src, modes[mode].dest, modes[mode].src, modes[mode].dest);
|
||
|
cellGcmSetBlendEquation(GcmCtx, modes[mode].op, modes[mode].op);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Pushes a Blend mode onto renderer.
|
||
|
virtual void PushBlendMode(BlendType mode)
|
||
|
{
|
||
|
// Blend modes need to be applied cumulatively, ideally through an extra RT texture.
|
||
|
// If the nested clip has a "Multiply" effect, and its parent has an "Add", the result
|
||
|
// of Multiply should be written to a buffer, and then used in Add.
|
||
|
|
||
|
// For now we only simulate it on one level -> we apply the last effect on top of stack.
|
||
|
// (Note that the current "top" element is BlendMode, it is not actually stored on stack).
|
||
|
// Although incorrect, this will at least ensure that parent's specified effect
|
||
|
// will be applied to children.
|
||
|
|
||
|
BlendModeStack.PushBack(BlendMode);
|
||
|
|
||
|
if ((mode > Blend_Layer) && (BlendMode != mode))
|
||
|
{
|
||
|
BlendMode = mode;
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Pops a blend mode, restoring it to the previous one.
|
||
|
virtual void PopBlendMode()
|
||
|
{
|
||
|
if (BlendModeStack.GetSize() != 0)
|
||
|
{
|
||
|
// Find the next top interesting mode.
|
||
|
BlendType newBlendMode = Blend_None;
|
||
|
|
||
|
for (SInt i = (SInt)BlendModeStack.GetSize()-1; i>=0; i--)
|
||
|
if (BlendModeStack[i] > Blend_Layer)
|
||
|
{
|
||
|
newBlendMode = BlendModeStack[i];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
BlendModeStack.PopBack();
|
||
|
|
||
|
if (newBlendMode != BlendMode)
|
||
|
{
|
||
|
BlendMode = newBlendMode;
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Stack was empty..
|
||
|
GFC_DEBUG_WARNING(1, "GRendererGL::PopBlendMode - blend mode stack is empty");
|
||
|
}
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
virtual void SetPerspective3D(const GMatrix3D &projMatIn)
|
||
|
{
|
||
|
ProjMatrix = projMatIn;
|
||
|
UVPMatricesChanged = 1;
|
||
|
}
|
||
|
|
||
|
virtual void SetView3D(const GMatrix3D &viewMatIn)
|
||
|
{
|
||
|
ViewMatrix = viewMatIn;
|
||
|
UVPMatricesChanged = 1;
|
||
|
}
|
||
|
|
||
|
virtual void SetStereoDisplay(StereoDisplay sDisplay, bool setstate)
|
||
|
{
|
||
|
S3DDisplay = sDisplay;
|
||
|
UVPMatricesChanged = 1;
|
||
|
|
||
|
if (setstate)
|
||
|
pCurRenderTarget->SetRenderTarget(S3DDisplay);
|
||
|
}
|
||
|
|
||
|
virtual void SetWorld3D(const GMatrix3D *pWorldMatIn)
|
||
|
{
|
||
|
pWorldMatrix = pWorldMatIn;
|
||
|
}
|
||
|
|
||
|
void UpdateStereoProjection()
|
||
|
{
|
||
|
Float eyeZ = -ViewMatrix.M_[3][2];
|
||
|
if (S3DDisplay == StereoLeft)
|
||
|
{
|
||
|
GMatrix3D left;
|
||
|
GetStereoProjectionMatrix(&left, NULL, ProjMatrix, eyeZ);
|
||
|
ProjMatrix = left;
|
||
|
}
|
||
|
else
|
||
|
if (S3DDisplay == StereoRight)
|
||
|
{
|
||
|
GMatrix3D right;
|
||
|
GetStereoProjectionMatrix(NULL, &right, ProjMatrix, eyeZ);
|
||
|
ProjMatrix = right;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void ApplyMatrix(const GRenderer::Matrix& m1)
|
||
|
{
|
||
|
#ifndef GFC_NO_3D
|
||
|
if (pWorldMatrix)
|
||
|
{
|
||
|
if (UVPMatricesChanged)
|
||
|
{
|
||
|
UpdateStereoProjection();
|
||
|
UVPMatricesChanged = 0;
|
||
|
UVPMatrix = UserMatrix;
|
||
|
UVPMatrix.Append(ViewMatrix);
|
||
|
UVPMatrix.Append(ProjMatrix);
|
||
|
|
||
|
if (RenderTargetStack.GetSize())
|
||
|
{
|
||
|
GMatrix2D vm1(BaseMatrix.M_[0][0], BaseMatrix.M_[0][1],
|
||
|
BaseMatrix.M_[1][0], BaseMatrix.M_[1][1],
|
||
|
BaseMatrix.M_[0][3], BaseMatrix.M_[1][3]);
|
||
|
|
||
|
GMatrix2D vm2(RenderTargetStack[0].ViewMatrix.M_[0][0], RenderTargetStack[0].ViewMatrix.M_[0][1],
|
||
|
RenderTargetStack[0].ViewMatrix.M_[1][0], RenderTargetStack[0].ViewMatrix.M_[1][1],
|
||
|
RenderTargetStack[0].ViewMatrix.M_[0][3], RenderTargetStack[0].ViewMatrix.M_[1][3]);
|
||
|
|
||
|
Adjust3DMatrixForRT(UVPMatrix, ProjMatrix, vm2, vm1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CurMatrix = GMatrix3D(m1);
|
||
|
CurMatrix.Append(*pWorldMatrix);
|
||
|
CurMatrix.Append(UVPMatrix);
|
||
|
CurMatrix.Transpose();
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
GRenderer::Matrix m(UserMatrix);
|
||
|
m.Prepend(m1);
|
||
|
|
||
|
GMatrix3D m3d;
|
||
|
Float* mat = m3d;
|
||
|
|
||
|
mat[0] = m.M_[0][0];
|
||
|
mat[4] = m.M_[1][0];
|
||
|
mat[1] = m.M_[0][1];
|
||
|
mat[5] = m.M_[1][1];
|
||
|
mat[10] = 1;
|
||
|
mat[3] = m.M_[0][2];
|
||
|
mat[7] = m.M_[1][2];
|
||
|
mat[15] = 1;
|
||
|
|
||
|
CurMatrix.MultiplyMatrix(BaseMatrix, m3d);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set the given color.
|
||
|
void ApplyColor(const GColor c)
|
||
|
{
|
||
|
float args[4];
|
||
|
|
||
|
if ((BlendMode == Blend_Multiply) ||
|
||
|
(BlendMode == Blend_Darken))
|
||
|
{
|
||
|
const float mult = 1.0f / 255.0f;
|
||
|
const float alpha = c.GetAlpha() * mult;
|
||
|
|
||
|
args[3] = gflerp(1.0f, c.GetRed() * mult, alpha);
|
||
|
args[2] = gflerp(1.0f, c.GetGreen() * mult, alpha);
|
||
|
args[1] = gflerp(1.0f, c.GetBlue() * mult, alpha);
|
||
|
args[0] = alpha;
|
||
|
|
||
|
cellGcmSetVertexData4f(GcmCtx, CgVShaders[CurVProgram].colori, args);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
args[3] = c.GetRed() * (1.0f / 255.0f);
|
||
|
args[2] = c.GetGreen() * (1.0f / 255.0f);
|
||
|
args[1] = c.GetBlue() * (1.0f / 255.0f);
|
||
|
args[0] = c.GetAlpha() * (1.0f / 255.0f);
|
||
|
|
||
|
cellGcmSetVertexData4f(GcmCtx, CgVShaders[CurVProgram].colori, args);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Don't fill on the {0 == left, 1 == right} side of a path.
|
||
|
void FillStyleDisable()
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].Disable();
|
||
|
}
|
||
|
// Don't draw a line on this path.
|
||
|
void LineStyleDisable()
|
||
|
{
|
||
|
CurrentStyles[LINE_STYLE].Disable();
|
||
|
}
|
||
|
|
||
|
// Set fill style for the left interior of the shape. If
|
||
|
// enable is false, turn off fill for the left interior.
|
||
|
void FillStyleColor(GColor color)
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].SetColor(CurrentCxform.Transform(color));
|
||
|
}
|
||
|
|
||
|
// Set the line style of the shape. If enable is false, turn
|
||
|
// off lines for following curve segments.
|
||
|
void LineStyleColor(GColor color)
|
||
|
{
|
||
|
CurrentStyles[LINE_STYLE].SetColor(CurrentCxform.Transform(color));
|
||
|
}
|
||
|
|
||
|
void FillStyleBitmap(const FillTexture *pfill)
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].SetBitmap(pfill, CurrentCxform);
|
||
|
}
|
||
|
|
||
|
// Sets the interpolated color/texture fill style used for shapes with EdgeAA.
|
||
|
void FillStyleGouraud(GouraudFillType gfill,
|
||
|
const FillTexture *ptexture0,
|
||
|
const FillTexture *ptexture1,
|
||
|
const FillTexture *ptexture2)
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].SetGouraudFill(gfill, ptexture0, ptexture1, ptexture2, CurrentCxform);
|
||
|
}
|
||
|
|
||
|
void SetVertexData(const void* pvertices, int numVertices, VertexFormat vf, CacheProvider *pcache)
|
||
|
{
|
||
|
pVertexData = pvertices;
|
||
|
VertexFmt = vf;
|
||
|
VertexArray = 0;
|
||
|
|
||
|
UInt32 size;
|
||
|
switch (vf)
|
||
|
{
|
||
|
case Vertex_XY16i: size = 2 * sizeof(short); break;
|
||
|
case Vertex_XY32f: size = 2 * sizeof(float); break;
|
||
|
case Vertex_XY16iC32: size = 2 * sizeof(short) + 4; break;
|
||
|
case Vertex_XY16iCF32: size = 2 * sizeof(short) + 8; break;
|
||
|
case -1: size = sizeof(GGlyphVertex); break;
|
||
|
default: return;
|
||
|
}
|
||
|
|
||
|
if (VA_size < size * numVertices || numVertices == 0)
|
||
|
return;
|
||
|
|
||
|
cellGcmSetWriteBackEndLabel(GcmCtx, VA_label, VA_lastv);
|
||
|
cellGcmFlush(GcmCtx);
|
||
|
|
||
|
// Two areas of the vertex buffer are available for writing:
|
||
|
// after any previous writes (> VA_end)
|
||
|
// up to the last rendered vertices (< pos)
|
||
|
|
||
|
UInt32 lv = *((volatile UInt32 *) cellGcmGetLabelAddress(VA_label));
|
||
|
UInt32 pos = lv & ((1 << VA_shift) - 1);
|
||
|
UInt32 lastv = VA_lastv & ((1 << VA_shift) - 1);
|
||
|
UInt32 count = lv >> VA_shift;
|
||
|
|
||
|
if (VA_end > VA_size)
|
||
|
pos = 0;
|
||
|
|
||
|
if (VA_end + numVertices * size <= VA_size &&
|
||
|
((pos <= lastv && count == VA_count) || pos >= VA_end + numVertices * size))
|
||
|
{
|
||
|
VA_start = VA_end;
|
||
|
}
|
||
|
else if (numVertices * size <= pos && pos <= lastv && count == VA_count)
|
||
|
{
|
||
|
VA_start = 0;
|
||
|
VA_count = (VA_count + 1) & ((1 << (32-VA_shift)) - 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
while( *((volatile UInt32 *) cellGcmGetLabelAddress(VA_label)) != VA_lastv)
|
||
|
sys_timer_usleep(10);
|
||
|
|
||
|
VA_start = 0;
|
||
|
VA_count = 0;
|
||
|
*((volatile UInt32 *) cellGcmGetLabelAddress(VA_label)) = 0;
|
||
|
}
|
||
|
|
||
|
if (pvertices)
|
||
|
memcpy(VA_base + VA_start, pvertices, numVertices * size);
|
||
|
VertexArray = 1;
|
||
|
VA_end = VA_start + numVertices * size;
|
||
|
VA_lastv = VA_end | ((VA_count << VA_shift) & ~((1 << VA_shift)-1));
|
||
|
|
||
|
// Test cache buffer management support.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_Vertex, (pvertices!=0),
|
||
|
numVertices, (((pvertices!=0)&&numVertices) ? *((SInt16*)pvertices) : 0) );
|
||
|
}
|
||
|
|
||
|
void SetIndexData(const void* pindices, int numIndices, IndexFormat idxf, CacheProvider *pcache)
|
||
|
{
|
||
|
pIndexData = pindices;
|
||
|
IndexArray = 0;
|
||
|
switch(idxf)
|
||
|
{
|
||
|
case Index_None:
|
||
|
IndexFmt = 0; break;
|
||
|
default:
|
||
|
IndexFmt = idxf; break;
|
||
|
}
|
||
|
|
||
|
// Test cache buffer management support.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_Index, (pindices!=0),
|
||
|
numIndices, (((pindices!=0)&&numIndices) ? *((SInt16*)pindices) : 0) );
|
||
|
}
|
||
|
|
||
|
void ReleaseCachedData(CachedData *pdata, CachedDataType type)
|
||
|
{
|
||
|
// Releases cached data that was allocated from the cache providers.
|
||
|
CacheList.ReleaseCachedData(pdata, type);
|
||
|
|
||
|
if (pdata->GetRendererData())
|
||
|
{
|
||
|
GBufferNode *pn = (GBufferNode*)pdata->GetRendererData();
|
||
|
|
||
|
Allocator->Free(pn->BufferH);
|
||
|
pn->RemoveNode();
|
||
|
delete pn;
|
||
|
pdata->SetRendererData(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void DrawIndexedTriList(int baseVertexIndex, int minVertexIndex, int numVertices,
|
||
|
int startIndex, int triangleCount)
|
||
|
{
|
||
|
GUNUSED2(minVertexIndex, numVertices);
|
||
|
|
||
|
if (!pVertexData || !pIndexData || !IndexFmt) // Must have vertex data.
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(!pVertexData, "GRendererPS3::DrawIndexedTriList failed, vertex data not specified");
|
||
|
GFC_DEBUG_WARNING(!pIndexData, "GRendererPS3::DrawIndexedTriList failed, index data not specified");
|
||
|
GFC_DEBUG_WARNING(!IndexFmt, "GRendererPS3::DrawIndexedTriList failed, index buffer format not specified");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Set up current style.
|
||
|
CurrentStyles[FILL_STYLE].Apply(this);
|
||
|
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
cellGcmSetVertexProgramParameter(GcmCtx, CgVShaders[CurVProgram].mvp, CurMatrix);
|
||
|
TransferShaders();
|
||
|
|
||
|
const void* pindices = (UByte*)(IndexArray ? 0 : pIndexData) + startIndex *
|
||
|
((IndexFmt == Index_16) ? sizeof(UInt16) : sizeof(UInt32));
|
||
|
UInt32 vertexBase = 0;
|
||
|
SInt vertexLoc = VA_location;
|
||
|
SInt vertexIndex = baseVertexIndex;
|
||
|
|
||
|
if (VertexArray)
|
||
|
{
|
||
|
vertexBase = VA_offset + VA_start;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vertexBase = VA_offset;
|
||
|
vertexIndex = 0;
|
||
|
}
|
||
|
|
||
|
// Gouraud colors
|
||
|
if (VertexFmt == Vertex_XY16iC32)
|
||
|
{
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, sizeof(VertexXY16iC32), 2, CELL_GCM_VERTEX_S32K,
|
||
|
vertexLoc, vertexBase + vertexIndex * sizeof(VertexXY16iC32));
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].colori, 0, sizeof(VertexXY16iC32), 4, CELL_GCM_VERTEX_UB,
|
||
|
vertexLoc, vertexBase + vertexIndex * sizeof(VertexXY16iC32) + 2 * sizeof(UInt16));
|
||
|
}
|
||
|
else if (VertexFmt == Vertex_XY16iCF32)
|
||
|
{
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, sizeof(VertexXY16iCF32), 2, CELL_GCM_VERTEX_S32K,
|
||
|
vertexLoc, vertexBase + vertexIndex * sizeof(VertexXY16iCF32));
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].colori, 0, sizeof(VertexXY16iCF32), 4, CELL_GCM_VERTEX_UB,
|
||
|
vertexLoc, vertexBase + vertexIndex * sizeof(VertexXY16iCF32) + 2 * sizeof(UInt16));
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].factori, 0, sizeof(VertexXY16iCF32), 4, CELL_GCM_VERTEX_UB,
|
||
|
vertexLoc, vertexBase + vertexIndex * sizeof(VertexXY16iCF32) + 2 * sizeof(UInt16) + 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, sizeof(SInt16) * 2, 2, CELL_GCM_VERTEX_S32K,
|
||
|
vertexLoc, vertexBase + vertexIndex * sizeof(SInt16) * 2);
|
||
|
}
|
||
|
|
||
|
cellGcmSetInvalidateVertexCache(GcmCtx);
|
||
|
|
||
|
if (CurrentStyles[FILL_STYLE].Fill.pTexture)
|
||
|
cellGcmSetInvalidateTextureCache(GcmCtx, CELL_GCM_INVALIDATE_TEXTURE);
|
||
|
|
||
|
if (!VertexArray)
|
||
|
{
|
||
|
UInt vsize;
|
||
|
if (VertexFmt == Vertex_XY16iC32)
|
||
|
vsize = sizeof(VertexXY16iC32);
|
||
|
else if (VertexFmt == Vertex_XY16iCF32)
|
||
|
vsize = sizeof(VertexXY16iCF32);
|
||
|
else
|
||
|
vsize = 4;
|
||
|
|
||
|
int trianglesPerCall = VA_size / (3 * vsize);
|
||
|
for (int j = 0; j < triangleCount; j += trianglesPerCall)
|
||
|
{
|
||
|
cellGcmSetWriteBackEndLabel(GcmCtx, VA_label, VA_lastv);
|
||
|
cellGcmFlush(GcmCtx);
|
||
|
|
||
|
while( *((volatile UInt32 *) cellGcmGetLabelAddress(VA_label)) != VA_lastv)
|
||
|
sys_timer_usleep(10);
|
||
|
|
||
|
VA_lastv = 1 + VA_size | (VA_count << VA_shift);
|
||
|
VA_count++;
|
||
|
|
||
|
int triangles;
|
||
|
|
||
|
if (j + trianglesPerCall >= triangleCount)
|
||
|
triangles = triangleCount - j;
|
||
|
else
|
||
|
triangles = trianglesPerCall;
|
||
|
|
||
|
if (IndexFmt == Index_16)
|
||
|
for (int i = 0; i < 3 * triangles; i++)
|
||
|
memcpy(VA_base + i * vsize,
|
||
|
((UByte*)pVertexData) + vsize * (baseVertexIndex + ((UInt16*)pindices)[i+j*3]), vsize);
|
||
|
else
|
||
|
for (int i = 0; i < 3 * triangles; i++)
|
||
|
memcpy(VA_base + i * vsize,
|
||
|
((UByte*)pVertexData) + vsize * (baseVertexIndex + ((UInt32*)pindices)[i+j*3]), vsize);
|
||
|
|
||
|
*((volatile UInt32 *)cellGcmGetLabelAddress(VA_label)) = 0;
|
||
|
cellGcmSetInvalidateVertexCache(GcmCtx);
|
||
|
cellGcmSetDrawArrays(GcmCtx, CELL_GCM_PRIMITIVE_TRIANGLES, 0, 3*triangles);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
VA_start = 0;
|
||
|
VA_end = VA_size + 1;
|
||
|
}
|
||
|
else if (IndexFmt == Index_16)
|
||
|
{
|
||
|
if (triangleCount * 6 > MaxCmdSize)
|
||
|
{
|
||
|
UInt16 *pindex = (UInt16*) pindices;
|
||
|
int maxtris = MaxCmdSize / 6;
|
||
|
for (int i = 0; i < triangleCount; i += maxtris)
|
||
|
{
|
||
|
int count = maxtris;
|
||
|
if (i + count >= triangleCount)
|
||
|
count = triangleCount - i;
|
||
|
cellGcmSetDrawInlineIndexArray16(GcmCtx, CELL_GCM_PRIMITIVE_TRIANGLES, 0, 3*count, pindex);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
|
||
|
pindex += 3 * count;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cellGcmSetDrawInlineIndexArray16(GcmCtx, CELL_GCM_PRIMITIVE_TRIANGLES, 0, 3*triangleCount, (UInt16*)pindices);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
}
|
||
|
else if (triangleCount * 12 > MaxCmdSize)
|
||
|
{
|
||
|
UInt32 *pindex = (UInt32*) pindices;
|
||
|
int maxtris = MaxCmdSize / 12;
|
||
|
for (int i = 0; i < triangleCount; i += maxtris)
|
||
|
{
|
||
|
int count = maxtris;
|
||
|
if (i + count >= triangleCount)
|
||
|
count = triangleCount - i;
|
||
|
cellGcmSetDrawInlineIndexArray32(GcmCtx, CELL_GCM_PRIMITIVE_TRIANGLES, 0, 3*count, pindex);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
|
||
|
pindex += 3 * count;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cellGcmSetDrawInlineIndexArray32(GcmCtx, CELL_GCM_PRIMITIVE_TRIANGLES, 0, 3*triangleCount, (UInt32*)pindices);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
RenderStats.Triangles += triangleCount;
|
||
|
TriangleCnt.AddCount(triangleCount);
|
||
|
|
||
|
if (VertexFmt == Vertex_XY16iC32)
|
||
|
{
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].colori, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
}
|
||
|
else if (VertexFmt == Vertex_XY16iCF32)
|
||
|
{
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].colori, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].factori, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Draw the line strip formed by the sequence of Points.
|
||
|
void DrawLineStrip(int baseVertexIndex, int lineCount)
|
||
|
{
|
||
|
if (!pVertexData) // Must have vertex data.
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(!pVertexData, "GRendererPS3::DrawLineStrip failed, vertex data not specified");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Set up current style.
|
||
|
CurrentStyles[LINE_STYLE].Apply(this);
|
||
|
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
cellGcmSetVertexProgramParameter(GcmCtx, CgVShaders[CurVProgram].mvp, CurMatrix);
|
||
|
TransferShaders();
|
||
|
|
||
|
UInt32 vertexBase = 0;
|
||
|
SInt vertexLoc = VA_location;
|
||
|
|
||
|
cellGcmSetInvalidateVertexCache(GcmCtx);
|
||
|
if (CurrentStyles[LINE_STYLE].Fill.pTexture)
|
||
|
cellGcmSetInvalidateTextureCache(GcmCtx, CELL_GCM_INVALIDATE_TEXTURE);
|
||
|
|
||
|
if (VertexArray)
|
||
|
{
|
||
|
vertexBase = VA_offset + VA_start;
|
||
|
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, sizeof(SInt16) * 2, 2, CELL_GCM_VERTEX_S32K,
|
||
|
vertexLoc, vertexBase + baseVertexIndex * sizeof(SInt16) * 2);
|
||
|
|
||
|
cellGcmSetDrawArrays(GcmCtx, CELL_GCM_PRIMITIVE_LINE_STRIP, 0, lineCount + 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, sizeof(SInt16) * 2, 2, CELL_GCM_VERTEX_S32K,
|
||
|
CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
|
||
|
cellGcmSetDrawInlineArray(GcmCtx, CELL_GCM_PRIMITIVE_LINE_STRIP, (lineCount + 1),
|
||
|
((UByte*)pVertexData) + baseVertexIndex * sizeof(SInt16) * 2);
|
||
|
}
|
||
|
|
||
|
RenderStats.Lines += lineCount;
|
||
|
RenderStats.Primitives++;
|
||
|
|
||
|
LineCnt.AddCount(lineCount);
|
||
|
DPLineCnt.AddCount(1);
|
||
|
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Draw a set of rectangles textured with the given bitmap, with the given color.
|
||
|
// Apply given transform; ignore any currently set transforms.
|
||
|
//
|
||
|
// Intended for textured glyph rendering.
|
||
|
void DrawBitmaps(BitmapDesc* pbitmapList, int listSize, int startIndex, int count,
|
||
|
const GTexture* pti, const Matrix& m,
|
||
|
CacheProvider *pcache)
|
||
|
{
|
||
|
if (!pbitmapList || !pti)
|
||
|
return;
|
||
|
|
||
|
// Test cache buffer management support.
|
||
|
// Optimized implementation could use this spot to set vertex buffer and/or initialize offset in it.
|
||
|
// Note that since bitmap lists are usually short, it would be a good idea to combine many of them
|
||
|
// into one buffer, instead of creating individual buffers for each pbitmapList data instance.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_BitmapList, (pbitmapList!=0),
|
||
|
listSize, (((pbitmapList!=0)&&listSize) ? ((SInt)pbitmapList->Coords.Left) : 0) );
|
||
|
|
||
|
cellGcmSetBlendEnable(GcmCtx, CELL_GCM_TRUE);
|
||
|
|
||
|
GTexturePS3Impl *ptex = (GTexturePS3Impl*)pti;
|
||
|
|
||
|
if (ptex->IsYUVTexture() == 1)
|
||
|
{
|
||
|
if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureYUVMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureYUV);
|
||
|
}
|
||
|
else if (ptex->IsYUVTexture() == 2)
|
||
|
{
|
||
|
if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureYUVAMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureYUVA);
|
||
|
}
|
||
|
else if ((ptex->Tex.format & 0x9F) == CELL_GCM_TEXTURE_B8)
|
||
|
SetPixelShader(PS_TextTexture);
|
||
|
else if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureColorMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureColor);
|
||
|
ApplyPShaderCxform(CurrentCxform);
|
||
|
SetVertexProgram(Vertex_None, 0);
|
||
|
|
||
|
ptex->Bind(0, Wrap_Clamp, Sample_Linear, !ptex->IsYUVTexture());
|
||
|
|
||
|
// Custom matrix per call.
|
||
|
ApplyMatrix(m);
|
||
|
|
||
|
cellGcmSetVertexProgramParameter(GcmCtx, CgVShaders[CurVProgram].mvp, CurMatrix);
|
||
|
TransferShaders();
|
||
|
|
||
|
SInt ibitmap = 0, ivertex = 0;
|
||
|
|
||
|
SetVertexData(0, count * 6, (VertexFormat)-1, 0);
|
||
|
|
||
|
if (!VertexArray)
|
||
|
{
|
||
|
UInt vsize = sizeof(GGlyphVertex);
|
||
|
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, sizeof(GGlyphVertex), 2, CELL_GCM_VERTEX_F,
|
||
|
VA_location, VA_offset);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].tci, 0, sizeof(GGlyphVertex), 2, CELL_GCM_VERTEX_F,
|
||
|
VA_location, VA_offset + sizeof(Float)*2);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].colori, 0, sizeof(GGlyphVertex), 4, CELL_GCM_VERTEX_UB,
|
||
|
VA_location, VA_offset + sizeof(Float)*4);
|
||
|
|
||
|
cellGcmSetInvalidateTextureCache(GcmCtx, CELL_GCM_INVALIDATE_TEXTURE);
|
||
|
|
||
|
int primsPerCall = VA_size / (6 * vsize);
|
||
|
for (int j = 0; j < count; j += primsPerCall)
|
||
|
{
|
||
|
cellGcmSetWriteBackEndLabel(GcmCtx, VA_label, VA_lastv);
|
||
|
cellGcmFlush(GcmCtx);
|
||
|
|
||
|
while( *((volatile UInt32 *) cellGcmGetLabelAddress(VA_label)) != VA_lastv)
|
||
|
sys_timer_usleep(10);
|
||
|
|
||
|
VA_start = 0;
|
||
|
VA_lastv = 1 + VA_size | (VA_count << VA_shift);
|
||
|
VA_count++;
|
||
|
|
||
|
int prims;
|
||
|
|
||
|
if (j + primsPerCall >= count)
|
||
|
prims = count - j;
|
||
|
else
|
||
|
prims = primsPerCall;
|
||
|
|
||
|
for(ivertex = 0, ibitmap = 0; ibitmap<prims; ibitmap++, ivertex+= 6)
|
||
|
{
|
||
|
BitmapDesc & bd = pbitmapList[ibitmap + startIndex + j];
|
||
|
GGlyphVertex* pv = ((GGlyphVertex *) VA_base) + ivertex;
|
||
|
|
||
|
// Triangle 1.
|
||
|
pv[0].SetVertex2D(bd.Coords.Left, bd.Coords.Top, bd.TextureCoords.Left, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[1].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[2].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, bd.Color);
|
||
|
// Triangle 2.
|
||
|
pv[3].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, bd.Color);
|
||
|
pv[4].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[5].SetVertex2D(bd.Coords.Right, bd.Coords.Bottom,bd.TextureCoords.Right, bd.TextureCoords.Bottom, bd.Color);
|
||
|
}
|
||
|
|
||
|
// Draw the generated triangles.
|
||
|
*((volatile UInt32 *) cellGcmGetLabelAddress(VA_label)) = 0;
|
||
|
cellGcmSetInvalidateVertexCache(GcmCtx);
|
||
|
cellGcmSetDrawArrays(GcmCtx, CELL_GCM_PRIMITIVE_TRIANGLES, 0, ivertex);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
VA_end = VA_size + 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, sizeof(GGlyphVertex), 2, CELL_GCM_VERTEX_F,
|
||
|
VA_location, VA_offset + VA_start);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].tci, 0, sizeof(GGlyphVertex), 2, CELL_GCM_VERTEX_F,
|
||
|
VA_location, VA_offset + VA_start + sizeof(Float)*2);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].colori, 0, sizeof(GGlyphVertex), 4, CELL_GCM_VERTEX_UB,
|
||
|
VA_location, VA_offset + VA_start + sizeof(Float)*4);
|
||
|
|
||
|
cellGcmSetInvalidateVertexCache(GcmCtx);
|
||
|
cellGcmSetInvalidateTextureCache(GcmCtx, CELL_GCM_INVALIDATE_TEXTURE);
|
||
|
|
||
|
for(ivertex = 0; ibitmap<count; ibitmap++, ivertex+= 6)
|
||
|
{
|
||
|
BitmapDesc & bd = pbitmapList[ibitmap + startIndex];
|
||
|
GGlyphVertex* pv = (GGlyphVertex *) (VA_base + VA_start) + ivertex;
|
||
|
|
||
|
// Triangle 1.
|
||
|
pv[0].SetVertex2D(bd.Coords.Left, bd.Coords.Top, bd.TextureCoords.Left, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[1].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[2].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, bd.Color);
|
||
|
// Triangle 2.
|
||
|
pv[3].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, bd.Color);
|
||
|
pv[4].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[5].SetVertex2D(bd.Coords.Right, bd.Coords.Bottom,bd.TextureCoords.Right, bd.TextureCoords.Bottom, bd.Color);
|
||
|
}
|
||
|
|
||
|
// Draw the generated triangles.
|
||
|
cellGcmSetDrawArrays(GcmCtx, CELL_GCM_PRIMITIVE_TRIANGLES, 0, ivertex);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].posi, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].tci, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
cellGcmSetVertexDataArray(GcmCtx, CgVShaders[CurVProgram].colori, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
|
||
|
|
||
|
RenderStats.Triangles += count * 2;
|
||
|
TriangleCnt.AddCount(count * 2);
|
||
|
}
|
||
|
|
||
|
void BeginSubmitMask(SubmitMaskMode maskMode)
|
||
|
{
|
||
|
// disable framebuffer writes
|
||
|
cellGcmSetColorMask(GcmCtx, 0);
|
||
|
cellGcmSetStencilTestEnable(GcmCtx, CELL_GCM_TRUE);
|
||
|
|
||
|
switch(maskMode)
|
||
|
{
|
||
|
case Mask_Clear:
|
||
|
cellGcmSetClearDepthStencil(GcmCtx, 0);
|
||
|
cellGcmSetClearSurface(GcmCtx, CELL_GCM_CLEAR_S);
|
||
|
|
||
|
cellGcmSetStencilFunc(GcmCtx, CELL_GCM_ALWAYS, 1, 1);
|
||
|
cellGcmSetStencilOp(GcmCtx, CELL_GCM_KEEP, CELL_GCM_KEEP, CELL_GCM_REPLACE);
|
||
|
StencilCounter = 1;
|
||
|
break;
|
||
|
|
||
|
case Mask_Increment:
|
||
|
cellGcmSetStencilFunc(GcmCtx, CELL_GCM_EQUAL, StencilCounter, 0xFF);
|
||
|
cellGcmSetStencilOp(GcmCtx, CELL_GCM_KEEP, CELL_GCM_KEEP, CELL_GCM_INCR);
|
||
|
StencilCounter++;
|
||
|
break;
|
||
|
|
||
|
case Mask_Decrement:
|
||
|
cellGcmSetStencilFunc(GcmCtx, CELL_GCM_EQUAL, StencilCounter, 0xFF);
|
||
|
cellGcmSetStencilOp(GcmCtx, CELL_GCM_KEEP, CELL_GCM_KEEP, CELL_GCM_DECR);
|
||
|
StencilCounter--;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
cellGcmSetStencilMask(GcmCtx, 0xFF);
|
||
|
RenderStats.Masks++;
|
||
|
MaskCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
void EndSubmitMask()
|
||
|
{
|
||
|
cellGcmSetColorMask(GcmCtx, CELL_GCM_COLOR_MASK_R|CELL_GCM_COLOR_MASK_G|CELL_GCM_COLOR_MASK_B|CELL_GCM_COLOR_MASK_A);
|
||
|
|
||
|
// We draw only where the (stencil == StencilCounter); i.e. where the mask was drawn.
|
||
|
// Don't change the stencil buffer
|
||
|
StencilEnabled = 1;
|
||
|
cellGcmSetStencilFunc(GcmCtx, CELL_GCM_EQUAL, StencilCounter, 0xFF);
|
||
|
cellGcmSetStencilOp(GcmCtx, CELL_GCM_KEEP, CELL_GCM_KEEP, CELL_GCM_KEEP);
|
||
|
}
|
||
|
|
||
|
void DisableMask()
|
||
|
{
|
||
|
cellGcmSetStencilTestEnable(GcmCtx, CELL_GCM_FALSE);
|
||
|
StencilEnabled = 0;
|
||
|
StencilCounter = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
virtual void GetRenderStats(Stats *pstats, bool resetStats)
|
||
|
{
|
||
|
if (pstats)
|
||
|
memcpy(pstats, &RenderStats, sizeof(Stats));
|
||
|
if (resetStats)
|
||
|
RenderStats.Clear();
|
||
|
}
|
||
|
|
||
|
virtual void GetStats(GStatBag* pbag, bool reset)
|
||
|
{
|
||
|
if (pbag)
|
||
|
{
|
||
|
pbag->Add(GStatRender_Texture_VMem, &TextureVMem);
|
||
|
pbag->Add(GStatRender_Buffer_VMem, &BufferVMem);
|
||
|
|
||
|
pbag->Add(GStatRender_TextureUpload_Cnt, &TextureUploadCnt);
|
||
|
pbag->Add(GStatRender_TextureUpdate_Cnt, &TextureUpdateCnt);
|
||
|
|
||
|
pbag->Add(GStatRender_DP_Line_Cnt, &DPLineCnt);
|
||
|
pbag->Add(GStatRender_DP_Triangle_Cnt, &DPTriangleCnt);
|
||
|
pbag->Add(GStatRender_Line_Cnt, &LineCnt);
|
||
|
pbag->Add(GStatRender_Triangle_Cnt, &TriangleCnt);
|
||
|
pbag->Add(GStatRender_Mask_Cnt, &MaskCnt);
|
||
|
pbag->Add(GStatRender_Filter_Cnt, &FilterCnt);
|
||
|
}
|
||
|
|
||
|
if (reset)
|
||
|
{
|
||
|
TextureUploadCnt.Reset();
|
||
|
TextureUpdateCnt.Reset();
|
||
|
|
||
|
DPLineCnt.Reset();
|
||
|
DPTriangleCnt.Reset();
|
||
|
LineCnt.Reset();
|
||
|
TriangleCnt.Reset();
|
||
|
MaskCnt.Reset();
|
||
|
FilterCnt.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void InitFragShader1 (PixelShaderType ps, const void *progin)
|
||
|
{
|
||
|
CgFShaders[ps].prog = (CGprogram)progin;
|
||
|
cellGcmCgInitProgram(CgFShaders[ps].prog);
|
||
|
|
||
|
CgFShaders[ps].cxmul = cellGcmCgGetNamedParameter (CgFShaders[ps].prog, "cmul");
|
||
|
CgFShaders[ps].cxadd = cellGcmCgGetNamedParameter (CgFShaders[ps].prog, "cadd");
|
||
|
|
||
|
CgFShaders[ps].tex[0] = cellGcmCgGetNamedParameter (CgFShaders[ps].prog, "tex");
|
||
|
CgFShaders[ps].tex[1] = cellGcmCgGetNamedParameter (CgFShaders[ps].prog, "tex1");
|
||
|
|
||
|
if (CgFShaders[ps].tex[0])
|
||
|
{
|
||
|
CgFShaders[ps].texi[0] = (CGresource)(cellGcmCgGetParameterResource(CgFShaders[ps].prog, CgFShaders[ps].tex[0]) - CG_TEXUNIT0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CgFShaders[ps].tex[0] = cellGcmCgGetNamedParameter (CgFShaders[ps].prog, "tex_y");
|
||
|
if (CgFShaders[ps].tex[0])
|
||
|
{
|
||
|
CgFShaders[ps].tex[2] = cellGcmCgGetNamedParameter (CgFShaders[ps].prog, "tex_u");
|
||
|
CgFShaders[ps].tex[3] = cellGcmCgGetNamedParameter (CgFShaders[ps].prog, "tex_v");
|
||
|
CgFShaders[ps].tex[4] = cellGcmCgGetNamedParameter (CgFShaders[ps].prog, "tex_a");
|
||
|
CgFShaders[ps].texi[0] = (CGresource)(cellGcmCgGetParameterResource(CgFShaders[ps].prog, CgFShaders[ps].tex[0]) - CG_TEXUNIT0);
|
||
|
CgFShaders[ps].texi[2] = (CGresource)(cellGcmCgGetParameterResource(CgFShaders[ps].prog, CgFShaders[ps].tex[2]) - CG_TEXUNIT0);
|
||
|
CgFShaders[ps].texi[3] = (CGresource)(cellGcmCgGetParameterResource(CgFShaders[ps].prog, CgFShaders[ps].tex[3]) - CG_TEXUNIT0);
|
||
|
if (CgFShaders[ps].tex[4])
|
||
|
CgFShaders[ps].texi[4] = (CGresource)(cellGcmCgGetParameterResource(CgFShaders[ps].prog, CgFShaders[ps].tex[4]) - CG_TEXUNIT0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (CgFShaders[ps].tex[1])
|
||
|
CgFShaders[ps].texi[1] = (CGresource)(cellGcmCgGetParameterResource(CgFShaders[ps].prog, CgFShaders[ps].tex[1]) - CG_TEXUNIT0);
|
||
|
|
||
|
void *uc, *io;
|
||
|
size_t ucsize;
|
||
|
cellGcmCgGetUCode(CgFShaders[ps].prog, &uc, &ucsize);
|
||
|
|
||
|
CgFShaders[ps].memobj = Allocator->Allocate(CELL_GCM_LOCATION_LOCAL, ucsize, 128);
|
||
|
CgFShaders[ps].offset = Allocator->GetOffset(CgFShaders[ps].memobj);
|
||
|
io = Allocator->Map(CgFShaders[ps].memobj);
|
||
|
memcpy(io, uc, ucsize);
|
||
|
Allocator->Unmap(CgFShaders[ps].memobj, io);
|
||
|
}
|
||
|
|
||
|
void InitFragShader (FragShaderType2 ps, const void *progin)
|
||
|
{
|
||
|
FilterShaders[ps].prog = (CGprogram)progin;
|
||
|
cellGcmCgInitProgram(FilterShaders[ps].prog);
|
||
|
|
||
|
FilterShaders[ps].uniforms[FSU_cxmul] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "cxmul");
|
||
|
FilterShaders[ps].uniforms[FSU_cxadd] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "cxadd");
|
||
|
|
||
|
FilterShaders[ps].tex[0] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "tex");
|
||
|
if (FilterShaders[ps].tex[0])
|
||
|
{
|
||
|
FilterShaders[ps].texi[0] = (CGresource)(cellGcmCgGetParameterResource(FilterShaders[ps].prog, FilterShaders[ps].tex[0]) - CG_TEXUNIT0);
|
||
|
|
||
|
FilterShaders[ps].uniforms[FSU_texscale] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "texscale");
|
||
|
FilterShaders[ps].uniforms[FSU_fsize] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "fsize");
|
||
|
FilterShaders[ps].uniforms[FSU_offset] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "offset");
|
||
|
FilterShaders[ps].uniforms[FSU_scolor] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "scolor");
|
||
|
FilterShaders[ps].uniforms[FSU_scolor2] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "scolor2");
|
||
|
FilterShaders[ps].uniforms[FSU_srctexscale] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "srctexscale");
|
||
|
FilterShaders[ps].tex[1] = cellGcmCgGetNamedParameter (FilterShaders[ps].prog, "srctex");
|
||
|
if (FilterShaders[ps].tex[1])
|
||
|
FilterShaders[ps].texi[1] = (CGresource)(cellGcmCgGetParameterResource(FilterShaders[ps].prog, FilterShaders[ps].tex[1]) - CG_TEXUNIT0);
|
||
|
}
|
||
|
|
||
|
void *uc, *io;
|
||
|
size_t ucsize;
|
||
|
cellGcmCgGetUCode(FilterShaders[ps].prog, &uc, &ucsize);
|
||
|
|
||
|
FilterShaders[ps].memobj = Allocator->Allocate(CELL_GCM_LOCATION_LOCAL, ucsize, 128);
|
||
|
FilterShaders[ps].offset = Allocator->GetOffset(FilterShaders[ps].memobj);
|
||
|
io = Allocator->Map(FilterShaders[ps].memobj);
|
||
|
memcpy(io, uc, ucsize);
|
||
|
Allocator->Unmap(FilterShaders[ps].memobj, io);
|
||
|
}
|
||
|
|
||
|
void InitVertexShader1 (SInt vs, const void *progin)
|
||
|
{
|
||
|
CgVShaders[vs].prog = (CGprogram) progin;
|
||
|
cellGcmCgInitProgram(CgVShaders[vs].prog);
|
||
|
CgVShaders[vs].texgenx[0] = cellGcmCgGetNamedParameter (CgVShaders[vs].prog, "texgenx0");
|
||
|
CgVShaders[vs].texgeny[0] = cellGcmCgGetNamedParameter (CgVShaders[vs].prog, "texgeny0");
|
||
|
CgVShaders[vs].texgenx[1] = cellGcmCgGetNamedParameter (CgVShaders[vs].prog, "texgenx1");
|
||
|
CgVShaders[vs].texgeny[1] = cellGcmCgGetNamedParameter (CgVShaders[vs].prog, "texgeny1");
|
||
|
CgVShaders[vs].factor = cellGcmCgGetNamedParameter (CgVShaders[vs].prog, "ifactor");
|
||
|
CgVShaders[vs].color = cellGcmCgGetNamedParameter (CgVShaders[vs].prog, "icolor");
|
||
|
CgVShaders[vs].pos = cellGcmCgGetNamedParameter (CgVShaders[vs].prog, "ipos");
|
||
|
CgVShaders[vs].tc = cellGcmCgGetNamedParameter (CgVShaders[vs].prog, "itc0");
|
||
|
CgVShaders[vs].mvp = cellGcmCgGetNamedParameter (CgVShaders[vs].prog, "mvp");
|
||
|
size_t ucsize;
|
||
|
cellGcmCgGetUCode(CgVShaders[vs].prog, &CgVShaders[vs].uc, &ucsize);
|
||
|
CgVShaders[vs].posi = (CGresource)(cellGcmCgGetParameterResource(CgVShaders[vs].prog, CgVShaders[vs].pos) - CG_ATTR0);
|
||
|
if (CgVShaders[vs].tc)
|
||
|
CgVShaders[vs].tci = (CGresource)(cellGcmCgGetParameterResource(CgVShaders[vs].prog, CgVShaders[vs].tc) - CG_ATTR0);
|
||
|
if (CgVShaders[vs].color)
|
||
|
CgVShaders[vs].colori = (CGresource)(cellGcmCgGetParameterResource(CgVShaders[vs].prog, CgVShaders[vs].color) - CG_ATTR0);
|
||
|
if (CgVShaders[vs].factor)
|
||
|
CgVShaders[vs].factori = (CGresource)(cellGcmCgGetParameterResource(CgVShaders[vs].prog, CgVShaders[vs].factor) - CG_ATTR0);
|
||
|
}
|
||
|
|
||
|
void InitVertexShader (VertexShaderType2 vs, const void *progin)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
virtual bool SetDependentVideoMode(const DependentVideoModeParams& params)
|
||
|
{
|
||
|
if (Allocator && Allocator != params.Alloc)
|
||
|
Clear();
|
||
|
|
||
|
Allocator = params.Alloc;
|
||
|
GcmCtx = params.Ctx;
|
||
|
MaxCmdSize = params.MaxCmdSize;
|
||
|
VMCFlags = params.vmConfigFlags;
|
||
|
|
||
|
CurVProgram = 0;
|
||
|
CurrentShader = 0;
|
||
|
|
||
|
if (params.VertexArraySize < 6 * 32)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "Vertex array too small");
|
||
|
return false;
|
||
|
}
|
||
|
if (VA_size != params.VertexArraySize || VA_memobj == 0)
|
||
|
{
|
||
|
VA_size = params.VertexArraySize;
|
||
|
VA_memobj = Allocator->Allocate(CELL_GCM_LOCATION_MAIN, VA_size, 64);
|
||
|
}
|
||
|
VA_base = 0;
|
||
|
VA_location = Allocator->GetLocation(VA_memobj);
|
||
|
VA_start = 0;
|
||
|
VA_end = 0;
|
||
|
VA_label = params.BaseLabel;
|
||
|
VA_lastv = 0;
|
||
|
VA_count = 0;
|
||
|
|
||
|
for (int i = 31; i; i--)
|
||
|
if ((1U << i) > VA_size)
|
||
|
VA_shift = i;
|
||
|
|
||
|
*((volatile UInt32 *) cellGcmGetLabelAddress(VA_label)) = 0;
|
||
|
|
||
|
ModeSet = 1;
|
||
|
if (CgFShaders[PS_TextTexture].memobj)
|
||
|
return 1;
|
||
|
|
||
|
InitVertexShader1(0, &_binary_v_1tex_vpo_start);
|
||
|
InitVertexShader1(1, &_binary_v_2tex_vpo_start);
|
||
|
InitVertexShader1(2, &_binary_v_text_vpo_start);
|
||
|
|
||
|
InitFragShader1 (PS_Solid, &_binary_p_solid_fpo_start);
|
||
|
InitFragShader1 (PS_TextTexture, &_binary_p_texta_fpo_start);
|
||
|
InitFragShader1 (PS_TextTextureColor, &_binary_p_text_fpo_start);
|
||
|
InitFragShader1 (PS_TextTextureColorMultiply, &_binary_p_textmul_fpo_start);
|
||
|
InitFragShader1 (PS_CxformTexture, &_binary_p_cxform_fpo_start);
|
||
|
InitFragShader1 (PS_CxformTextureMultiply, &_binary_p_cxformmul_fpo_start);
|
||
|
|
||
|
InitFragShader1 (PS_CxformGouraud, &_binary_p_cxg_fpo_start);
|
||
|
InitFragShader1 (PS_CxformGouraudMultiply, &_binary_p_cxgm_fpo_start);
|
||
|
InitFragShader1 (PS_CxformGouraudNoAddAlpha, &_binary_p_cxgna_fpo_start);
|
||
|
InitFragShader1 (PS_CxformGouraudMultiplyNoAddAlpha, &_binary_p_cxgmna_fpo_start);
|
||
|
InitFragShader1 (PS_CxformGouraudTexture, &_binary_p_cxgt_fpo_start);
|
||
|
InitFragShader1 (PS_CxformGouraudMultiplyTexture, &_binary_p_cxgtm_fpo_start);
|
||
|
InitFragShader1 (PS_Cxform2Texture, &_binary_p_cxg2t_fpo_start);
|
||
|
InitFragShader1 (PS_CxformMultiply2Texture, &_binary_p_cxg2tm_fpo_start);
|
||
|
|
||
|
#ifndef GFC_NO_YUV_TEXTURES
|
||
|
InitFragShader1 (PS_TextTextureYUV, &_binary_p_cxformyuv_fpo_start);
|
||
|
InitFragShader1 (PS_TextTextureYUVMultiply, &_binary_p_cxformyuvmul_fpo_start);
|
||
|
InitFragShader1 (PS_TextTextureYUVA, &_binary_p_cxformyuva_fpo_start);
|
||
|
InitFragShader1 (PS_TextTextureYUVAMultiply, &_binary_p_cxformyuvamul_fpo_start);
|
||
|
#endif
|
||
|
|
||
|
PS3InitShaders(this);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Returns back to original mode (cleanup)
|
||
|
virtual bool ResetVideoMode()
|
||
|
{
|
||
|
ModeSet = 0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
virtual DisplayStatus CheckDisplayStatus() const
|
||
|
{
|
||
|
return ModeSet ? DisplayStatus_Ok : DisplayStatus_NoModeSet;
|
||
|
}
|
||
|
|
||
|
virtual void RemoveAllTextures()
|
||
|
{
|
||
|
// Remove/notify all
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
while (Textures.pFirst != &Textures)
|
||
|
((GTexturePS3Impl*)Textures.pFirst)->RemoveFromRenderer();
|
||
|
}
|
||
|
|
||
|
}; // end class GRendererPS3Impl
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ***** GTexturePS3 implementation
|
||
|
|
||
|
GTexturePS3Impl::GTexturePS3Impl(GRendererPS3Impl *prenderer)
|
||
|
: GTexturePS3(&prenderer->Textures)
|
||
|
{
|
||
|
pRenderer = prenderer;
|
||
|
TexMem = 0;
|
||
|
Tex.width = Tex.height = Tex.pitch = 0;
|
||
|
}
|
||
|
|
||
|
GTexturePS3Impl::~GTexturePS3Impl()
|
||
|
{
|
||
|
ReleaseTexture();
|
||
|
if (!pRenderer)
|
||
|
return;
|
||
|
GLock::Locker gruad(&pRenderer->TexturesLock);
|
||
|
if (pFirst)
|
||
|
RemoveNode();
|
||
|
}
|
||
|
|
||
|
// Obtains the renderer that create TextureInfo
|
||
|
GRenderer* GTexturePS3Impl::GetRenderer() const
|
||
|
{
|
||
|
return pRenderer;
|
||
|
}
|
||
|
bool GTexturePS3Impl::IsDataValid() const
|
||
|
{
|
||
|
return (TexMem != 0);
|
||
|
}
|
||
|
|
||
|
// Remove texture from renderer, notifies renderer destruction
|
||
|
void GTexturePS3Impl::RemoveFromRenderer()
|
||
|
{
|
||
|
if (AddRef_NotZero())
|
||
|
{
|
||
|
ReleaseTexture();
|
||
|
pRenderer = 0;
|
||
|
CallHandlers(ChangeHandler::Event_RendererReleased);
|
||
|
if (pNext) // We may have been released by user
|
||
|
RemoveNode();
|
||
|
Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pRenderer = 0;
|
||
|
|
||
|
if (pNext) // We may have been released by user
|
||
|
RemoveNode();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Releases texture and clears values
|
||
|
void GTexturePS3Impl::ReleaseTexture()
|
||
|
{
|
||
|
if (TexMem)
|
||
|
pRenderer->Allocator->Free(TexMem);
|
||
|
TexMem = 0;
|
||
|
Tex.width = Tex.height = Tex.pitch = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Forward declarations for sampling/mipmaps
|
||
|
void HardwareResample(int bytesPerPixel, int srcWidth, int srcHeight, UByte* psrcData, int dstWidth, int dstHeight);
|
||
|
UByte* SoftwareResample(int bytesPerPixel, int srcWidth, int srcHeight, int srcPitch, UByte* psrcData, int dstWidth, int dstHeight);
|
||
|
void GenerateMipmaps(unsigned internalFormat, unsigned inputFormat, int bytesPerPixel, GImageBase* pim);
|
||
|
|
||
|
bool GTexturePS3Impl::InitTexture(CellGcmTexture *pTex, bool unused)
|
||
|
{
|
||
|
GUNUSED(unused);
|
||
|
ReleaseTexture();
|
||
|
|
||
|
Tex = *pTex;
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static UByte* LoadTextureSzBlock(UByte *pdest, const UByte *psrc, UInt w, UInt h, SInt bpp, SInt pitch, UInt x, UInt y, UInt b)
|
||
|
{
|
||
|
if (b == 1)
|
||
|
{
|
||
|
switch (bpp)
|
||
|
{
|
||
|
case 4:
|
||
|
pdest[0] = psrc[y*pitch+x*4+3];
|
||
|
pdest[1] = psrc[y*pitch+x*4+0];
|
||
|
pdest[2] = psrc[y*pitch+x*4+1];
|
||
|
pdest[3] = psrc[y*pitch+x*4+2];
|
||
|
return pdest + 4;
|
||
|
|
||
|
case 3:
|
||
|
pdest[0] = 255;
|
||
|
pdest[1] = psrc[y*pitch+x*3+0];
|
||
|
pdest[2] = psrc[y*pitch+x*3+1];
|
||
|
pdest[3] = psrc[y*pitch+x*3+2];
|
||
|
return pdest + 4;
|
||
|
|
||
|
case 1:
|
||
|
pdest[0] = psrc[y*pitch+x];
|
||
|
return pdest + 1;
|
||
|
|
||
|
default:
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdest = LoadTextureSzBlock(pdest, psrc, w,h,bpp,pitch, x, y, b-1);
|
||
|
pdest = LoadTextureSzBlock(pdest, psrc, w,h,bpp,pitch, x + (1<<(b-2)), y, b-1);
|
||
|
pdest = LoadTextureSzBlock(pdest, psrc, w,h,bpp,pitch, x, y + (1<<(b-2)), b-1);
|
||
|
return LoadTextureSzBlock(pdest, psrc, w,h,bpp,pitch, x + (1<<(b-2)), y + (1<<(b-2)), b-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline UByte* LoadTextureSz(UByte *pdest, const UByte *psrc, UInt w, UInt h, SInt bpp, SInt pitch)
|
||
|
{
|
||
|
UInt lw = 0; while (w != (1U << lw)) lw++;
|
||
|
UInt lh = 0; while (h != (1U << lh)) lh++;
|
||
|
|
||
|
if (w == h)
|
||
|
return LoadTextureSzBlock(pdest, psrc, w,h,bpp,pitch, 0,0,lw+1);
|
||
|
else if (w > h)
|
||
|
{
|
||
|
for (UInt i = 0; i < (1U << (lw-lh)); i++)
|
||
|
pdest = LoadTextureSzBlock(pdest, psrc, w,h,bpp,pitch, i<<lh, 0, lh+1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (UInt i = 0; i < (1U << (lh-lw)); i++)
|
||
|
pdest = LoadTextureSzBlock(pdest, psrc, w,h,bpp,pitch, 0, i<<lw, lw+1);
|
||
|
}
|
||
|
|
||
|
return pdest;
|
||
|
}
|
||
|
|
||
|
static UByte* LoadTexture(UByte *pdest, CellGcmTexture *ptex, const UByte *psrc, UInt w, UInt h, SInt bpp, SInt pitch)
|
||
|
{
|
||
|
if (ptex->pitch == 0)
|
||
|
return LoadTextureSz(pdest,psrc,w,h,bpp,pitch);
|
||
|
|
||
|
switch (bpp)
|
||
|
{
|
||
|
case 1:
|
||
|
for (UInt j = 0; j < h; j++, psrc += pitch, pdest += ptex->pitch)
|
||
|
memcpy(pdest, psrc, w*bpp);
|
||
|
return pdest;
|
||
|
case 4:
|
||
|
for (UInt j = 0; j < h; j++, psrc += pitch, pdest += ptex->pitch)
|
||
|
for (UInt i = 0; i < w; i++)
|
||
|
{
|
||
|
pdest[i*4+0] = psrc[i*4+3];
|
||
|
pdest[i*4+1] = psrc[i*4+0];
|
||
|
pdest[i*4+2] = psrc[i*4+1];
|
||
|
pdest[i*4+3] = psrc[i*4+2];
|
||
|
}
|
||
|
return pdest;
|
||
|
case 3:
|
||
|
for (UInt j = 0; j < h; j++, psrc += pitch, pdest += ptex->pitch)
|
||
|
for (UInt i = 0; i < w; i++)
|
||
|
{
|
||
|
pdest[i*4+0] = 255;
|
||
|
pdest[i*4+1] = psrc[i*3+0];
|
||
|
pdest[i*4+2] = psrc[i*3+1];
|
||
|
pdest[i*4+3] = psrc[i*3+2];
|
||
|
}
|
||
|
return pdest;
|
||
|
}
|
||
|
GASSERT(0);
|
||
|
return pdest;
|
||
|
}
|
||
|
|
||
|
bool GTexturePS3Impl::InitTexture(GImageBase* pim, UInt usage)
|
||
|
{
|
||
|
// Delete old data
|
||
|
ReleaseTexture();
|
||
|
if (!pim)
|
||
|
{
|
||
|
// Kill texture
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Determine format
|
||
|
UInt bytesPerPixel=0;
|
||
|
GImage::ImageFormat destFmt = pim->Format;
|
||
|
|
||
|
if (pim->Format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
bytesPerPixel = 4;
|
||
|
Tex.format = CELL_GCM_TEXTURE_A8R8G8B8 | CELL_GCM_TEXTURE_NR;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
bytesPerPixel = 3;
|
||
|
destFmt = GImage::Image_ARGB_8888;
|
||
|
Tex.format = CELL_GCM_TEXTURE_D8R8G8B8 | CELL_GCM_TEXTURE_NR;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_A_8)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
Tex.format = CELL_GCM_TEXTURE_B8 | CELL_GCM_TEXTURE_NR;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_DXT1)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
Tex.format = CELL_GCM_TEXTURE_COMPRESSED_DXT1 | CELL_GCM_TEXTURE_NR;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_DXT3)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
Tex.format = CELL_GCM_TEXTURE_COMPRESSED_DXT23 | CELL_GCM_TEXTURE_NR;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_DXT5)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
Tex.format = CELL_GCM_TEXTURE_COMPRESSED_DXT45 | CELL_GCM_TEXTURE_NR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Unsupported format
|
||
|
GASSERT(0);
|
||
|
}
|
||
|
|
||
|
UInt w = pim->Width;
|
||
|
UInt h = pim->Height;
|
||
|
|
||
|
UInt ww = 1; while (ww < w) { ww <<= 1; }
|
||
|
UInt hh = 1; while (hh < h) { hh <<= 1; }
|
||
|
if (ww != w || hh != h)
|
||
|
{
|
||
|
Tex.format |= CELL_GCM_TEXTURE_LN;
|
||
|
|
||
|
switch (pim->Format)
|
||
|
{
|
||
|
case GImage::Image_DXT1:
|
||
|
Tex.pitch = ((w+3)/4) * 8;
|
||
|
break;
|
||
|
case GImage::Image_DXT3:
|
||
|
case GImage::Image_DXT5:
|
||
|
Tex.pitch = ((w+3)/4) * 16;
|
||
|
break;
|
||
|
case GImage::Image_RGB_888:
|
||
|
Tex.pitch = w*4;
|
||
|
break;
|
||
|
default:
|
||
|
Tex.pitch = pim->Pitch;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Tex.format |= CELL_GCM_TEXTURE_SZ;
|
||
|
Tex.pitch = 0;
|
||
|
}
|
||
|
|
||
|
// Create the texture.
|
||
|
UPInt tsize = Tex.pitch ? (Tex.pitch * h) : GImage::GetMipMapLevelSize(destFmt, w, h);
|
||
|
|
||
|
Tex.mipmap = 1;
|
||
|
Tex.width = w;
|
||
|
Tex.height = h;
|
||
|
Tex.depth = 1;
|
||
|
Tex.cubemap = CELL_GCM_FALSE;
|
||
|
Tex.dimension = CELL_GCM_TEXTURE_DIMENSION_2;
|
||
|
|
||
|
if (pim->Format == GImage::Image_A_8)
|
||
|
Tex.remap = CELL_GCM_REMAP_MODE (CELL_GCM_TEXTURE_REMAP_ORDER_XYXY,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_R,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_A,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_G,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_B,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_ONE,
|
||
|
CELL_GCM_TEXTURE_REMAP_ONE,
|
||
|
CELL_GCM_TEXTURE_REMAP_ONE);
|
||
|
else
|
||
|
Tex.remap = CELL_GCM_REMAP_MODE (CELL_GCM_TEXTURE_REMAP_ORDER_XYXY,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_A,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_R,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_G,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_B,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP);
|
||
|
|
||
|
if (pim->Format == GImage::Image_A_8)
|
||
|
{
|
||
|
UInt wtmp = w, htmp = h;
|
||
|
|
||
|
do {
|
||
|
wtmp = wtmp >> 1;
|
||
|
htmp = htmp >> 1;
|
||
|
if (wtmp < 1) wtmp = 1;
|
||
|
if (htmp < 1) htmp = 1;
|
||
|
|
||
|
if (Tex.pitch == 0)
|
||
|
tsize += GImage::GetMipMapLevelSize(destFmt, wtmp, htmp);
|
||
|
else
|
||
|
tsize += Tex.pitch * htmp;
|
||
|
Tex.mipmap++;
|
||
|
} while (wtmp > 1 || htmp > 1);
|
||
|
}
|
||
|
else if (pim->MipMapCount > 1)
|
||
|
{
|
||
|
UInt wtmp = w, htmp = h;
|
||
|
if (Tex.pitch == 0)
|
||
|
for (UInt i = 0; i < pim->MipMapCount; i++)
|
||
|
{
|
||
|
wtmp = wtmp >> 1;
|
||
|
htmp = htmp >> 1;
|
||
|
if (wtmp < 1) wtmp = 1;
|
||
|
if (htmp < 1) htmp = 1;
|
||
|
tsize += GImage::GetMipMapLevelSize(destFmt, wtmp, htmp);
|
||
|
}
|
||
|
else if (pim->IsDataCompressed())
|
||
|
{
|
||
|
UInt blockSize = (pim->Format == GImage::Image_DXT1 ? 8 : 16);
|
||
|
for (UInt i = 0; i < pim->MipMapCount; i++)
|
||
|
{
|
||
|
htmp = htmp >> 1;
|
||
|
if (htmp < 1) htmp = 1;
|
||
|
tsize += ((htmp+3)/4) * blockSize * Tex.pitch;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
for (UInt i = 0; i < pim->MipMapCount; i++)
|
||
|
{
|
||
|
htmp = htmp >> 1;
|
||
|
if (htmp < 1) htmp = 1;
|
||
|
tsize += htmp * Tex.pitch;
|
||
|
}
|
||
|
|
||
|
Tex.mipmap = pim->MipMapCount;
|
||
|
}
|
||
|
|
||
|
TexMem = pRenderer->Allocator->Allocate(CELL_GCM_LOCATION_LOCAL, tsize, 128);
|
||
|
void *pTexData = pRenderer->Allocator->Map(TexMem);
|
||
|
UByte *pdest = (UByte*)pTexData;
|
||
|
|
||
|
Tex.offset = pRenderer->Allocator->GetOffset(TexMem);
|
||
|
Tex.location = pRenderer->Allocator->GetLocation(TexMem);
|
||
|
|
||
|
if (pim->MipMapCount <= 1 && !pim->IsDataCompressed() && Tex.mipmap > 1)
|
||
|
{
|
||
|
UByte *psrc = (UByte*) GALLOC(pim->Pitch * h, GStat_Default_Mem);
|
||
|
memcpy(psrc, pim->pData, pim->Pitch * h);
|
||
|
|
||
|
pdest = LoadTexture(pdest, &Tex, psrc, w, h, bytesPerPixel, pim->Pitch);
|
||
|
|
||
|
if (Tex.mipmap > 1)
|
||
|
do {
|
||
|
GRendererPS3Impl::MakeNextMiplevel(&w, &h, psrc, bytesPerPixel);
|
||
|
pdest = LoadTexture(pdest, &Tex, psrc, w, h, bytesPerPixel, w*bytesPerPixel);
|
||
|
} while (w > 1 || h > 1);
|
||
|
|
||
|
GFREE(psrc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Use original image directly.
|
||
|
UInt level = 0;
|
||
|
do {
|
||
|
UInt mipW, mipH, mipPitch;
|
||
|
const UByte* pdata = pim->GetMipMapLevelData(level, &mipW, &mipH, &mipPitch);
|
||
|
if (pdata == 0) //????
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererPS3: can't find mipmap level in texture");
|
||
|
break;
|
||
|
}
|
||
|
if (pim->IsDataCompressed())
|
||
|
{
|
||
|
if (Tex.pitch)
|
||
|
{
|
||
|
UInt bw = (mipW+3)/4;
|
||
|
UInt bh = (mipH+3)/4;
|
||
|
UInt blockSize = (pim->Format == GImage::Image_DXT1 ? 8 : 16);
|
||
|
for (UInt j = 0; j < bh; j++, pdata += bw*blockSize, pdest += Tex.pitch)
|
||
|
memcpy(pdest, pdata, bw*blockSize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
memcpy(pdest, pdata, GImage::GetMipMapLevelSize(pim->Format, mipW, mipH));
|
||
|
pdest += GImage::GetMipMapLevelSize(pim->Format, mipW, mipH);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdest = LoadTexture(pdest, &Tex, pdata, mipW, mipH, bytesPerPixel, mipPitch);
|
||
|
}
|
||
|
level++;
|
||
|
} while(level < pim->MipMapCount && level < Tex.mipmap);
|
||
|
}
|
||
|
GASSERT(pdest <= (UByte*)pTexData+tsize);
|
||
|
|
||
|
pRenderer->Allocator->Unmap(TexMem, pTexData);
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool GTexturePS3Impl::InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage)
|
||
|
{
|
||
|
ReleaseTexture();
|
||
|
|
||
|
// Determine format
|
||
|
UInt bytesPerPixel=0;
|
||
|
int destFmt = format;
|
||
|
|
||
|
if (format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
bytesPerPixel = 4;
|
||
|
Tex.format = CELL_GCM_TEXTURE_A8R8G8B8 | CELL_GCM_TEXTURE_NR | CELL_GCM_TEXTURE_LN;
|
||
|
}
|
||
|
else if (format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
bytesPerPixel = 4;
|
||
|
destFmt = GImage::Image_ARGB_8888;
|
||
|
Tex.format = CELL_GCM_TEXTURE_D8R8G8B8 | CELL_GCM_TEXTURE_NR | CELL_GCM_TEXTURE_LN;
|
||
|
}
|
||
|
else if (format == GImage::Image_A_8)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
Tex.format = CELL_GCM_TEXTURE_B8 | CELL_GCM_TEXTURE_NR | CELL_GCM_TEXTURE_LN;
|
||
|
}
|
||
|
else if (format == GImage::Image_DepthStencil)
|
||
|
{
|
||
|
bytesPerPixel = 4;
|
||
|
Tex.format = CELL_GCM_TEXTURE_DEPTH24_D8;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Unsupported format
|
||
|
GASSERT(0);
|
||
|
}
|
||
|
|
||
|
// Create the texture.
|
||
|
Tex.mipmap = 1 + mipmaps;
|
||
|
Tex.pitch = width * bytesPerPixel;
|
||
|
Tex.width = width;
|
||
|
Tex.height = height;
|
||
|
Tex.depth = 1;
|
||
|
Tex.cubemap = CELL_GCM_FALSE;
|
||
|
Tex.dimension = CELL_GCM_TEXTURE_DIMENSION_2;
|
||
|
|
||
|
if (format == GImage::Image_A_8)
|
||
|
Tex.remap = CELL_GCM_REMAP_MODE (CELL_GCM_TEXTURE_REMAP_ORDER_XYXY,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_R,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_A,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_G,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_B,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_ONE,
|
||
|
CELL_GCM_TEXTURE_REMAP_ONE,
|
||
|
CELL_GCM_TEXTURE_REMAP_ONE);
|
||
|
else
|
||
|
Tex.remap = CELL_GCM_REMAP_MODE (CELL_GCM_TEXTURE_REMAP_ORDER_XYXY,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_A,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_R,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_G,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_B,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP);
|
||
|
|
||
|
UPInt tsize = Tex.pitch * height;
|
||
|
UInt wtmp = width, htmp = height;
|
||
|
|
||
|
for (int i = 0; i < mipmaps; i++)
|
||
|
{
|
||
|
wtmp = wtmp >> 1;
|
||
|
htmp = htmp >> 1;
|
||
|
if (wtmp < 1) wtmp = 1;
|
||
|
if (htmp < 1) htmp = 1;
|
||
|
|
||
|
tsize += Tex.pitch * htmp * bytesPerPixel;
|
||
|
}
|
||
|
|
||
|
TexMem = pRenderer->Allocator->Allocate(CELL_GCM_LOCATION_LOCAL, tsize, 128);
|
||
|
|
||
|
Tex.offset = pRenderer->Allocator->GetOffset(TexMem);
|
||
|
Tex.location = pRenderer->Allocator->GetLocation(TexMem);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void GTexturePS3Impl::Update(int level, int n, const UpdateRect *rects, const GImageBase *pim)
|
||
|
{
|
||
|
if ((pRenderer->VMCFlags & GRendererPS3::VMConfig_FastTexUpdate) == 0)
|
||
|
{
|
||
|
// wait on rendering for old texture contents
|
||
|
volatile UInt32* label = ((volatile UInt32 *) cellGcmGetLabelAddress(pRenderer->VA_label));
|
||
|
cellGcmSetWriteTextureLabel(pRenderer->GcmCtx, pRenderer->VA_label, pRenderer->VA_lastv);
|
||
|
cellGcmFlush(pRenderer->GcmCtx);
|
||
|
|
||
|
while( *label != pRenderer->VA_lastv)
|
||
|
{
|
||
|
sys_timer_usleep(10);
|
||
|
}
|
||
|
|
||
|
pRenderer->VA_start = 0;
|
||
|
pRenderer->VA_lastv = (1 + pRenderer->VA_size) | (pRenderer->VA_count << pRenderer->VA_shift);
|
||
|
pRenderer->VA_count++;
|
||
|
}
|
||
|
|
||
|
|
||
|
UInt bpp = 0;
|
||
|
|
||
|
if (pim->Format == GImage::Image_ARGB_8888)
|
||
|
bpp = 4;
|
||
|
else if (pim->Format == GImage::Image_RGB_888)
|
||
|
bpp = 3;
|
||
|
else if (pim->Format == GImage::Image_A_8)
|
||
|
bpp = 1;
|
||
|
else
|
||
|
GASSERT(0);
|
||
|
|
||
|
UByte *pTexData = (UByte*)pRenderer->Allocator->Map(TexMem);
|
||
|
|
||
|
int h = Tex.height;
|
||
|
|
||
|
for (int i = 0; i < level; i++)
|
||
|
{
|
||
|
pTexData += Tex.pitch * h;
|
||
|
h >>= 1;
|
||
|
if (h < 1)
|
||
|
h = 1;
|
||
|
}
|
||
|
|
||
|
if (bpp == 3)
|
||
|
{
|
||
|
GASSERT(0);
|
||
|
}
|
||
|
else
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
for (int j = 0; j < rects[i].src.Height(); j++)
|
||
|
memcpy(pTexData + Tex.pitch * (rects[i].dest.y + j) + bpp * rects[i].dest.x,
|
||
|
pim->pData + pim->Pitch * (j + rects[i].src.Top) + pim->GetBytesPerPixel() * rects[i].src.Left,
|
||
|
rects[i].src.Width() * bpp);
|
||
|
}
|
||
|
|
||
|
pRenderer->Allocator->Unmap(TexMem, pTexData);
|
||
|
|
||
|
cellGcmSetInvalidateTextureCache(pRenderer->GcmCtx, CELL_GCM_INVALIDATE_TEXTURE);
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int GTexturePS3Impl::Map(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GASSERT(level <= Tex.mipmap && n > 0 && maps);
|
||
|
|
||
|
UInt bpp = 0;
|
||
|
if ((Tex.format & 0x9F) == CELL_GCM_TEXTURE_B8)
|
||
|
bpp = 1;
|
||
|
else
|
||
|
bpp = 4;
|
||
|
|
||
|
UByte *pTexData = (UByte*)pRenderer->Allocator->Map(TexMem);
|
||
|
|
||
|
int h = Tex.height;
|
||
|
int w = Tex.width;
|
||
|
|
||
|
for (int i = 0; i < level; i++)
|
||
|
{
|
||
|
pTexData += Tex.pitch * h;
|
||
|
h >>= 1;
|
||
|
if (h < 1)
|
||
|
h = 1;
|
||
|
w >>= 1;
|
||
|
if (w < 1)
|
||
|
w = 1;
|
||
|
}
|
||
|
maps[0].width = w;
|
||
|
maps[0].height = h;
|
||
|
maps[0].pitch = w * bpp;
|
||
|
maps[0].pData = pTexData;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool GTexturePS3Impl::Unmap(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GASSERT(level <= Tex.mipmap && n > 0 && maps);
|
||
|
|
||
|
UByte *pTexData = maps[0].pData;
|
||
|
int h = Tex.height;
|
||
|
|
||
|
for (int i = 0; i < level; i++)
|
||
|
{
|
||
|
pTexData -= Tex.pitch * h;
|
||
|
h >>= 1;
|
||
|
if (h < 1)
|
||
|
h = 1;
|
||
|
}
|
||
|
pRenderer->Allocator->Unmap(TexMem, pTexData);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// GTexturePS3Impl implementation
|
||
|
|
||
|
// Creates an OpenGL texture of the specified dst dimensions, from a
|
||
|
// resampled version of the given src image. Does a bilinear
|
||
|
// resampling to create the dst image.
|
||
|
UByte* SoftwareResample(
|
||
|
int format,
|
||
|
int srcWidth,
|
||
|
int srcHeight,
|
||
|
int srcPitch,
|
||
|
UByte* psrcData,
|
||
|
int dstWidth,
|
||
|
int dstHeight)
|
||
|
{
|
||
|
UByte* rescaled = (UByte*)GALLOC(dstWidth * dstHeight * 4, GStat_Default_Mem);
|
||
|
|
||
|
switch(format)
|
||
|
{
|
||
|
case GImage::Image_RGB_888:
|
||
|
GRenderer::ResizeImage(&rescaled[0], dstWidth, dstHeight, dstWidth * 3,
|
||
|
psrcData, srcWidth, srcHeight, srcPitch,
|
||
|
GRenderer::ResizeRgbToRgb);
|
||
|
break;
|
||
|
|
||
|
case GImage::Image_ARGB_8888:
|
||
|
GRenderer::ResizeImage(&rescaled[0], dstWidth, dstHeight, dstWidth * 4,
|
||
|
psrcData, srcWidth, srcHeight, srcPitch,
|
||
|
GRenderer::ResizeRgbaToRgba);
|
||
|
break;
|
||
|
|
||
|
case GImage::Image_A_8:
|
||
|
GRenderer::ResizeImage(&rescaled[0], dstWidth, dstHeight, dstWidth,
|
||
|
psrcData, srcWidth, srcHeight, srcPitch,
|
||
|
GRenderer::ResizeGray);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return rescaled;
|
||
|
}
|
||
|
|
||
|
void GTexturePS3Impl::Bind(int stageIndex0, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps)
|
||
|
{
|
||
|
int stageIndex = stageIndex0 < 0 ? (-stageIndex0-1) : pRenderer->CgFShaders[pRenderer->CurrentShader].texi[stageIndex0];
|
||
|
|
||
|
cellGcmSetTexture(pRenderer->GcmCtx, stageIndex, &Tex);
|
||
|
|
||
|
if (WrapMode == GRenderer::Wrap_Clamp)
|
||
|
cellGcmSetTextureAddress(pRenderer->GcmCtx, stageIndex, CELL_GCM_TEXTURE_CLAMP_TO_EDGE, CELL_GCM_TEXTURE_CLAMP_TO_EDGE,
|
||
|
CELL_GCM_TEXTURE_CLAMP_TO_EDGE,
|
||
|
CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL, CELL_GCM_TEXTURE_ZFUNC_NEVER, 0);
|
||
|
else
|
||
|
cellGcmSetTextureAddress(pRenderer->GcmCtx, stageIndex, CELL_GCM_TEXTURE_WRAP, CELL_GCM_TEXTURE_WRAP,
|
||
|
CELL_GCM_TEXTURE_CLAMP_TO_EDGE,
|
||
|
CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL, CELL_GCM_TEXTURE_ZFUNC_NEVER, 0);
|
||
|
|
||
|
cellGcmSetTextureControl(pRenderer->GcmCtx, stageIndex, CELL_GCM_TRUE, 0, 12 << 8, CELL_GCM_TEXTURE_MAX_ANISO_1);
|
||
|
|
||
|
// Lod bias is 1:4:8 signed fixed point; -0.5 = 0x1f80
|
||
|
cellGcmSetTextureFilter(pRenderer->GcmCtx, stageIndex, useMipmaps ? 0x1f80 : 0, (SampleMode == GRenderer::Sample_Point)
|
||
|
? CELL_GCM_TEXTURE_NEAREST : (useMipmaps ? CELL_GCM_TEXTURE_LINEAR_LINEAR : CELL_GCM_TEXTURE_LINEAR),
|
||
|
(SampleMode == GRenderer::Sample_Point) ? CELL_GCM_TEXTURE_NEAREST : CELL_GCM_TEXTURE_LINEAR,
|
||
|
CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX);
|
||
|
}
|
||
|
|
||
|
#ifndef GFC_NO_YUV_TEXTURES
|
||
|
|
||
|
// ***** GTexturePS3 implementation
|
||
|
|
||
|
GTexturePS3ImplYUV::GTexturePS3ImplYUV(GRendererPS3Impl *prenderer) : GTexturePS3Impl(prenderer)
|
||
|
{
|
||
|
TexMemUVA[0] = TexMemUVA[1] = TexMemUVA[2] = 0;
|
||
|
}
|
||
|
|
||
|
GTexturePS3ImplYUV::~GTexturePS3ImplYUV()
|
||
|
{
|
||
|
ReleaseTexture();
|
||
|
}
|
||
|
|
||
|
bool GTexturePS3ImplYUV::InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage)
|
||
|
{
|
||
|
ReleaseTexture();
|
||
|
GASSERT(mipmaps == 0);
|
||
|
GUNUSED(usage);
|
||
|
|
||
|
Tex.format = CELL_GCM_TEXTURE_B8 | CELL_GCM_TEXTURE_NR | CELL_GCM_TEXTURE_LN;
|
||
|
Tex.mipmap = 1;
|
||
|
Tex.pitch = width;
|
||
|
Tex.width = width;
|
||
|
Tex.height = height;
|
||
|
Tex.depth = 1;
|
||
|
Tex.cubemap = CELL_GCM_FALSE;
|
||
|
Tex.dimension = CELL_GCM_TEXTURE_DIMENSION_2;
|
||
|
|
||
|
Tex.remap = CELL_GCM_REMAP_MODE(CELL_GCM_TEXTURE_REMAP_ORDER_XYXY,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_A,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_R,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_G,
|
||
|
CELL_GCM_TEXTURE_REMAP_FROM_B,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP,
|
||
|
CELL_GCM_TEXTURE_REMAP_REMAP);
|
||
|
|
||
|
TexMem = pRenderer->Allocator->Allocate(CELL_GCM_LOCATION_MAIN, Tex.pitch * Tex.height, 128);
|
||
|
|
||
|
Tex.offset = pRenderer->Allocator->GetOffset(TexMem);
|
||
|
Tex.location = pRenderer->Allocator->GetLocation(TexMem);
|
||
|
|
||
|
for (int i = 0; i < (format == GImage::Image_ARGB_8888 ? 3 : 2); i++)
|
||
|
{
|
||
|
TexUVA[i] = Tex;
|
||
|
if (i != 2)
|
||
|
{
|
||
|
TexUVA[i].width = Tex.width >> 1;
|
||
|
TexUVA[i].height = Tex.height >> 1;
|
||
|
TexUVA[i].pitch = Tex.width >> 1;
|
||
|
}
|
||
|
|
||
|
TexMemUVA[i] = pRenderer->Allocator->Allocate(CELL_GCM_LOCATION_MAIN, TexUVA[i].pitch * TexUVA[i].height, 128);
|
||
|
|
||
|
TexUVA[i].offset = pRenderer->Allocator->GetOffset(TexMemUVA[i]);
|
||
|
TexUVA[i].location = pRenderer->Allocator->GetLocation(TexMemUVA[i]);
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void GTexturePS3ImplYUV::Bind(int stageIndex0, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps)
|
||
|
{
|
||
|
GASSERT(stageIndex0 == 0);
|
||
|
|
||
|
int stageIndex[4];
|
||
|
stageIndex[0] = pRenderer->CgFShaders[pRenderer->CurrentShader].texi[0];
|
||
|
stageIndex[1] = pRenderer->CgFShaders[pRenderer->CurrentShader].texi[2];
|
||
|
stageIndex[2] = pRenderer->CgFShaders[pRenderer->CurrentShader].texi[3];
|
||
|
|
||
|
cellGcmSetTexture(pRenderer->GcmCtx, stageIndex[0], &Tex);
|
||
|
cellGcmSetTexture(pRenderer->GcmCtx, stageIndex[1], TexUVA);
|
||
|
cellGcmSetTexture(pRenderer->GcmCtx, stageIndex[2], TexUVA+1);
|
||
|
|
||
|
if (TexMemUVA[2])
|
||
|
{
|
||
|
stageIndex[3] = pRenderer->CgFShaders[pRenderer->CurrentShader].texi[4];
|
||
|
cellGcmSetTexture(pRenderer->GcmCtx, stageIndex[3], TexUVA+2);
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < (TexMemUVA[2] ? 4 : 3); i++)
|
||
|
{
|
||
|
if (WrapMode == GRenderer::Wrap_Clamp)
|
||
|
cellGcmSetTextureAddress(pRenderer->GcmCtx, stageIndex[i], CELL_GCM_TEXTURE_CLAMP_TO_EDGE, CELL_GCM_TEXTURE_CLAMP_TO_EDGE,
|
||
|
CELL_GCM_TEXTURE_CLAMP_TO_EDGE,
|
||
|
CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL, CELL_GCM_TEXTURE_ZFUNC_NEVER, 0);
|
||
|
else
|
||
|
cellGcmSetTextureAddress(pRenderer->GcmCtx, stageIndex[i], CELL_GCM_TEXTURE_WRAP, CELL_GCM_TEXTURE_WRAP,
|
||
|
CELL_GCM_TEXTURE_CLAMP_TO_EDGE,
|
||
|
CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL, CELL_GCM_TEXTURE_ZFUNC_NEVER, 0);
|
||
|
|
||
|
cellGcmSetTextureControl(pRenderer->GcmCtx, stageIndex[i], CELL_GCM_TRUE, 0, 12 << 8, CELL_GCM_TEXTURE_MAX_ANISO_1);
|
||
|
|
||
|
// Lod bias is 1:4:8 signed fixed point; -0.5 = 0x1f80
|
||
|
cellGcmSetTextureFilter(pRenderer->GcmCtx, stageIndex[i], useMipmaps ? 0x1f80 : 0, (SampleMode == GRenderer::Sample_Point)
|
||
|
? CELL_GCM_TEXTURE_NEAREST : (useMipmaps ? CELL_GCM_TEXTURE_LINEAR_LINEAR : CELL_GCM_TEXTURE_LINEAR),
|
||
|
(SampleMode == GRenderer::Sample_Point) ? CELL_GCM_TEXTURE_NEAREST : CELL_GCM_TEXTURE_LINEAR,
|
||
|
CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GTexturePS3ImplYUV::ReleaseTexture()
|
||
|
{
|
||
|
if (TexMem)
|
||
|
pRenderer->Allocator->Free(TexMem);
|
||
|
TexMem = 0;
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
if (TexMemUVA[i])
|
||
|
pRenderer->Allocator->Free(TexMemUVA[i]);
|
||
|
TexMemUVA[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int GTexturePS3ImplYUV::Map(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GASSERT(level == 0 && n >= 3 && maps);
|
||
|
|
||
|
maps[0].width = Tex.width;
|
||
|
maps[0].height = Tex.height;
|
||
|
maps[0].pitch = Tex.width;
|
||
|
maps[0].pData = (UByte*)pRenderer->Allocator->Map(TexMem);
|
||
|
|
||
|
maps[1].width = Tex.width >> 1;
|
||
|
maps[1].height = Tex.height >> 1;
|
||
|
maps[1].pitch = Tex.width >> 1;
|
||
|
maps[1].pData = (UByte*)pRenderer->Allocator->Map(TexMemUVA[0]);
|
||
|
|
||
|
maps[2].width = Tex.width >> 1;
|
||
|
maps[2].height = Tex.height >> 1;
|
||
|
maps[2].pitch = Tex.width >> 1;
|
||
|
maps[2].pData = (UByte*)pRenderer->Allocator->Map(TexMemUVA[1]);
|
||
|
|
||
|
if (n >= 4 && TexMemUVA[2])
|
||
|
{
|
||
|
maps[3].width = Tex.width;
|
||
|
maps[3].height = Tex.height;
|
||
|
maps[3].pitch = Tex.width;
|
||
|
maps[3].pData = (UByte*)pRenderer->Allocator->Map(TexMemUVA[2]);
|
||
|
return 4;
|
||
|
}
|
||
|
else
|
||
|
return 3;
|
||
|
}
|
||
|
|
||
|
bool GTexturePS3ImplYUV::Unmap(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GASSERT(level == 0 && n >= 3 && maps);
|
||
|
|
||
|
pRenderer->Allocator->Unmap(TexMem, maps[0].pData);
|
||
|
pRenderer->Allocator->Unmap(TexMemUVA[0], maps[1].pData);
|
||
|
pRenderer->Allocator->Unmap(TexMemUVA[1], maps[2].pData);
|
||
|
if (TexMemUVA[2] && n >= 4)
|
||
|
pRenderer->Allocator->Unmap(TexMemUVA[2], maps[3].pData);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
GRenderTargetPS3Impl::~GRenderTargetPS3Impl()
|
||
|
{
|
||
|
if (!pRenderer)
|
||
|
return;
|
||
|
GLock::Locker gruad(&pRenderer->TexturesLock);
|
||
|
if (pFirst)
|
||
|
RemoveNode();
|
||
|
}
|
||
|
|
||
|
GRenderTargetPS3Impl::GRenderTargetPS3Impl(GRendererPS3Impl* prenderer) : GRenderTargetPS3(&prenderer->RenderTargets), pRenderer(prenderer)
|
||
|
{
|
||
|
IsTemp = 0;
|
||
|
ActualHeight = 0;
|
||
|
Tiled = 0;
|
||
|
}
|
||
|
|
||
|
GRenderer* GRenderTargetPS3Impl::GetRenderer() const
|
||
|
{
|
||
|
return pRenderer;
|
||
|
}
|
||
|
|
||
|
void GRenderTargetPS3Impl::RemoveFromRenderer()
|
||
|
{
|
||
|
pRenderer = 0;
|
||
|
|
||
|
if (AddRef_NotZero())
|
||
|
{
|
||
|
pTexture = 0;
|
||
|
pStencilTexture = 0;
|
||
|
CallHandlers(ChangeHandler::Event_RendererReleased);
|
||
|
if (pNext) // We may have been released by user.
|
||
|
RemoveNode();
|
||
|
Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pNext) // We may have been released by user.
|
||
|
RemoveNode();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool GRenderTargetPS3Impl::InitRenderTarget(GTexture *ptarget, GTexture* pdepth, GTexture* pstencil)
|
||
|
{
|
||
|
pTexture = (GTexturePS3Impl*)ptarget;
|
||
|
TargetWidth = pTexture->Tex.width;
|
||
|
TargetHeight = pTexture->Tex.height;
|
||
|
|
||
|
UInt32 pitch = (TargetWidth * 4 + 63) & ~63;
|
||
|
|
||
|
Surf.colorFormat = CELL_GCM_SURFACE_A8R8G8B8; // xxx
|
||
|
Surf.colorTarget = CELL_GCM_SURFACE_TARGET_0;
|
||
|
Surf.colorLocation[0] = pTexture->Tex.location;
|
||
|
Surf.colorOffset[0] = pTexture->Tex.offset;
|
||
|
Surf.colorPitch[0] = pTexture->Tex.pitch;
|
||
|
|
||
|
Surf.colorLocation[1] = CELL_GCM_LOCATION_LOCAL;
|
||
|
Surf.colorLocation[2] = CELL_GCM_LOCATION_LOCAL;
|
||
|
Surf.colorLocation[3] = CELL_GCM_LOCATION_LOCAL;
|
||
|
Surf.colorOffset[1] = 0;
|
||
|
Surf.colorOffset[2] = 0;
|
||
|
Surf.colorOffset[3] = 0;
|
||
|
Surf.colorPitch[1] = 64;
|
||
|
Surf.colorPitch[2] = 64;
|
||
|
Surf.colorPitch[3] = 64;
|
||
|
|
||
|
if (pdepth)
|
||
|
pStencilTexture = (GTexturePS3Impl*)pdepth;
|
||
|
else if (pstencil)
|
||
|
pStencilTexture = (GTexturePS3Impl*)pstencil;
|
||
|
|
||
|
if (pStencilTexture)
|
||
|
{
|
||
|
Surf.depthFormat = CELL_GCM_SURFACE_Z24S8;
|
||
|
Surf.depthLocation = pStencilTexture->Tex.location;
|
||
|
Surf.depthOffset = pStencilTexture->Tex.offset;
|
||
|
Surf.depthPitch = pitch;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Surf.depthFormat = CELL_GCM_SURFACE_Z24S8;
|
||
|
Surf.depthLocation = CELL_GCM_LOCATION_LOCAL;
|
||
|
Surf.depthOffset = 0;
|
||
|
Surf.depthPitch = 64;
|
||
|
}
|
||
|
|
||
|
Surf.type = pTexture->Tex.format & CELL_GCM_TEXTURE_SZ ? CELL_GCM_SURFACE_SWIZZLE : CELL_GCM_SURFACE_PITCH;
|
||
|
Surf.antialias = CELL_GCM_SURFACE_CENTER_1;
|
||
|
|
||
|
Surf.width = pTexture->Tex.width;
|
||
|
Surf.height = pTexture->Tex.height;
|
||
|
Surf.x = 0;
|
||
|
Surf.y = 0;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool GRenderTargetPS3Impl::InitRenderTarget(PS3RenderTargetParams params)
|
||
|
{
|
||
|
pTexture = 0;
|
||
|
pStencilTexture = 0;
|
||
|
Surf = *params.Surface;
|
||
|
ActualHeight = params.ActualHeight;
|
||
|
Tiled = params.Tiled;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void GRenderTargetPS3Impl::SetRenderTarget(GRenderer::StereoDisplay disp)
|
||
|
{
|
||
|
if (ActualHeight)
|
||
|
{
|
||
|
CellGcmSurface SetSurf (Surf);
|
||
|
|
||
|
Surf.height = ActualHeight;
|
||
|
if (disp == GRenderer::StereoRight)
|
||
|
{
|
||
|
if (Tiled)
|
||
|
{
|
||
|
UInt AlignedLineOffset = (30 + ActualHeight) & ~7;
|
||
|
SetSurf.colorOffset[0] += Surf.colorPitch[0] * AlignedLineOffset;
|
||
|
SetSurf.y += (30 + ActualHeight) - AlignedLineOffset;
|
||
|
}
|
||
|
else
|
||
|
SetSurf.colorOffset[0] += Surf.colorPitch[0] * (30 + ActualHeight);
|
||
|
}
|
||
|
|
||
|
cellGcmSetSurface(pRenderer->GcmCtx, &SetSurf);
|
||
|
}
|
||
|
else
|
||
|
cellGcmSetSurface(pRenderer->GcmCtx, &Surf);
|
||
|
}
|
||
|
|
||
|
#include "PS3/PS3Shaders.cpp"
|
||
|
|
||
|
// Factory.
|
||
|
GRendererPS3* GRendererPS3::CreateRenderer()
|
||
|
{
|
||
|
return new GRendererPS3Impl;
|
||
|
}
|
||
|
|