/********************************************************************** Filename : GRendererOGLImplPS3.cpp Content : OpenGL renderer implementation - NV_Cg Created : Authors : Copyright : (c) 2001-2005 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. **********************************************************************/ struct CgShader { CGprogram prog; CGparameter cxmul, cxadd; CGparameter tex[5]; }; struct CgVProgram { CGprogram prog; CGparameter mvp; CGparameter texgenx[2], texgeny[2]; CGparameter factor; }; class GTextureOGLImplPS3 : public GTextureOGLImpl { GLuint PboId; UPInt TexSize; UInt TexPitch; public: GTextureOGLImplPS3(GRendererOGLImpl *prenderer) : GTextureOGLImpl(prenderer) { PboId = 0; } void ReleaseTextureId () { GTextureOGLImpl::ReleaseTextureId(); glDeleteBuffers(1, &PboId); } bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage) { ReleaseTextureId(); GLint internalFormat=0; GLint datatype = GL_UNSIGNED_BYTE; UInt bpp = 0; if (format == GImage::Image_ARGB_8888 || format == GImage::Image_RGB_888) { internalFormat = GL_RGBA8; datatype = GL_UNSIGNED_INT_8_8_8_8; bpp = 4; } else if (format == GImage::Image_A_8) { #ifdef GFC_GL_NO_ALPHA_TEXTURES internalFormat = GL_RGBA8; datatype = GL_UNSIGNED_INT_8_8_8_8; bpp = 4; #else internalFormat = GL_ALPHA; bpp = 1; #endif } else GASSERT(0); InitTextureId(GL_LINEAR); TextureFmt = internalFormat; TextureData = datatype; TexWidth = width; TexHeight = height; TexPitch = width * bpp; TexSize = TexPitch * height; Mipmaps = 1+mipmaps; 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; TexSize += TexPitch * htmp * bpp; } glGenBuffers(1, &PboId); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, PboId); glBufferData(GL_TEXTURE_REFERENCE_BUFFER_SCE, TexSize, 0, GL_STATIC_DRAW); glTextureReferenceSCE(GL_TEXTURE_2D, mipmaps+1, width, height, 1, internalFormat, TexPitch, 0); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0); CallHandlers(ChangeHandler::Event_DataChange); return 1; } void Update(int level, int n, const UpdateRect *rects, const GImageBase *pim) { 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); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, PboId); // cannot use WRITE_ONLY since the old buffer contents are not preserved UByte *pTexData = (UByte*)glMapBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, GL_READ_WRITE); int h = TexHeight; for (int i = 0; i < level; i++) { pTexData += TexPitch * h; h >>= 1; if (h < 1) h = 1; } if (bpp == 3) { for (int i = 0; i < n; i++) { GRect rect = rects[i].src; UByte *pdest = pTexData + rects[i].dest.y * TexPitch + rects[i].dest.x * 4; for (int j = 0; j < rect.Height(); j++) for (int k = 0; k < rect.Width(); k++) { pdest[j * TexPitch + k * 4 +0] = pim->pData[(j + rect.Top) * pim->Pitch + (k + rect.Left) * 3 +0]; pdest[j * TexPitch + k * 4 +1] = pim->pData[(j + rect.Top) * pim->Pitch + (k + rect.Left) * 3 +1]; pdest[j * TexPitch + k * 4 +2] = pim->pData[(j + rect.Top) * pim->Pitch + (k + rect.Left) * 3 +2]; pdest[j * TexPitch + k * 4 +3] = 255; } } } #ifdef GFC_GL_NO_ALPHA_TEXTURES else if (bpp == 1) { for (int i = 0; i < n; i++) { GRect rect = rects[i].src; UByte *pdest = pTexData + rects[i].dest.y * TexPitch + rects[i].dest.x * 4; for (int j = 0; j < rect.Height(); j++) for (int k = 0; k < rect.Width(); k++) { pdest[j * TexPitch + k * 4 +0] = pdest[j * TexPitch + k * 4 +1] = pdest[j * TexPitch + k * 4 +2] = 255; pdest[j * TexPitch + k * 4 +3] = pim->pData[(j + rect.Top) * pim->Pitch + (k + rect.Left)]; } } } #endif else for (int i = 0; i < n; i++) { for (int j = 0; j < rects[i].src.Height(); j++) memcpy(pTexData + TexPitch * (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); } if (!glUnmapBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE)) GASSERT(0); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0); } int Map(int level, int n, MapRect* maps, int flags) { GUNUSED(flags); GASSERT(level < Mipmaps && n > 0 && maps); UInt bpp=0; switch (TextureFmt) { case GL_RGBA8: bpp = 4; break; case GL_ALPHA: case GL_LUMINANCE: bpp = 1; break; } glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, PboId); UByte *pTexData = (UByte*)glMapBuffer (GL_TEXTURE_REFERENCE_BUFFER_SCE, flags & Map_KeepOld ? GL_READ_WRITE : GL_WRITE_ONLY); UInt mipw = TexWidth, miph = TexHeight; for (int i = 0; i < level; i++) { pTexData += TexPitch * miph; mipw >>= 1; miph >>= 1; if (mipw < 1) mipw = 1; if (miph < 1) miph = 1; } maps[0].width = mipw; maps[0].height = miph; maps[0].pitch = mipw * bpp; maps[0].pData = pTexData; glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0); return 1; } bool Unmap(int level, int n, MapRect* maps, int flags) { GUNUSED2(flags,n); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, PboId); int ret = glUnmapBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0); return ret; } void Bind(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps); }; class GTextureOGLImplPS3YUV : public GTextureOGLImplYUV { public: GLuint PboId; UInt TexSizeYA, TexSizeUV, TexPitch; GTextureOGLImplPS3YUV(GRendererOGLImpl *prenderer) : GTextureOGLImplYUV(prenderer) { PboId = 0; } virtual bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage) { if (!pRenderer) return 0; GASSERT(mipmaps == 0); ReleaseTextureId(); TexWidth = TexPitch = width; TexHeight = height; DeleteTexture = 1; UInt ntex = (format == GImage::Image_ARGB_8888 ? 4 : 3); Mipmaps = mipmaps+1; TextureFmt = GL_LUMINANCE; TextureData = GL_UNSIGNED_BYTE; TexSizeYA = TexPitch * height; TexSizeUV = (TexWidth>>1) * (TexHeight>>1); UPInt TexSize = TexSizeYA + TexSizeUV * 2; if (format == GImage::Image_ARGB_8888) TexSize += TexSizeYA; glGenBuffers(1, &PboId); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, PboId); glBufferData(GL_TEXTURE_REFERENCE_BUFFER_SCE, TexSize, 0, GL_STATIC_DRAW); glGenTextures(1, (GLuint*)&TextureId); glGenTextures(ntex-1, TextureUVA); glBindTexture(GL_TEXTURE_2D, TextureId); glTextureReferenceSCE(GL_TEXTURE_2D, mipmaps+1, width, height, 1, TextureFmt, TexPitch, 0); glBindTexture(GL_TEXTURE_2D, TextureUVA[0]); glTextureReferenceSCE(GL_TEXTURE_2D, mipmaps+1, width>>1, height>>1, 1, TextureFmt, TexPitch>>1, TexSizeYA); glBindTexture(GL_TEXTURE_2D, TextureUVA[1]); glTextureReferenceSCE(GL_TEXTURE_2D, mipmaps+1, width>>1, height>>1, 1, TextureFmt, TexPitch>>1, TexSizeYA+TexSizeUV); if (format == GImage::Image_ARGB_8888) { glBindTexture(GL_TEXTURE_2D, TextureUVA[2]); glTextureReferenceSCE(GL_TEXTURE_2D, mipmaps+1, width, height, 1, TextureFmt, TexPitch, TexSizeYA+TexSizeUV*2); } glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0); CallHandlers(ChangeHandler::Event_DataChange); return 1; } virtual int Map(int level, int n, MapRect* maps, int flags) { GUNUSED(flags); GASSERT(n >= (TextureUVA[2] ? 4 : 3) && maps); GASSERT(level == 0); n = TextureUVA[2] ? 4 : 3; glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, PboId); UByte *pTexData = (UByte*)glMapBuffer (GL_TEXTURE_REFERENCE_BUFFER_SCE, flags & Map_KeepOld ? GL_READ_WRITE : GL_WRITE_ONLY); maps[0].width = TexWidth; maps[0].height = TexHeight; maps[0].pitch = TexPitch; maps[0].pData = pTexData; maps[1].width = TexWidth>>1; maps[1].height = TexHeight>>1; maps[1].pitch = TexPitch>>1; maps[1].pData = pTexData + TexSizeYA; maps[2].width = TexWidth>>1; maps[2].height = TexHeight>>1; maps[2].pitch = TexPitch>>1; maps[2].pData = pTexData + TexSizeYA + TexSizeUV; if (n == 4) { maps[3].width = TexWidth; maps[3].height = TexHeight; maps[3].pitch = TexPitch; maps[3].pData = pTexData + TexSizeYA + TexSizeUV*2; } glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0); return n; } virtual bool Unmap(int level, int n, MapRect* maps, int flags) { GUNUSED4(flags,n,maps,level); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, PboId); int ret = glUnmapBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE); glBindBuffer(GL_TEXTURE_REFERENCE_BUFFER_SCE, 0); return ret; } virtual void ReleaseTextureId() { GTextureOGLImplYUV::ReleaseTextureId(); glDeleteBuffers(1, &PboId); } void Bind(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps); }; /* Compiled shaders */ extern int _binary_p_cxform_fpo_cgelf_start; extern int _binary_p_cxformmul_fpo_cgelf_start; extern int _binary_p_cxg2t_fpo_cgelf_start; extern int _binary_p_cxg2tm_fpo_cgelf_start; extern int _binary_p_cxg_fpo_cgelf_start; extern int _binary_p_cxgm_fpo_cgelf_start; extern int _binary_p_cxgmna_fpo_cgelf_start; extern int _binary_p_cxgna_fpo_cgelf_start; extern int _binary_p_cxgt_fpo_cgelf_start; extern int _binary_p_cxgtm_fpo_cgelf_start; extern int _binary_p_text_fpo_cgelf_start; extern int _binary_p_texta_fpo_cgelf_start; extern int _binary_p_textmul_fpo_cgelf_start; extern int _binary_v_1tex_vpo_cgelf_start; extern int _binary_v_2tex_vpo_cgelf_start; #ifndef GFC_NO_YUV_TEXTURES extern int _binary_p_cxformyuv_fpo_cgelf_start; extern int _binary_p_cxformyuvmul_fpo_cgelf_start; extern int _binary_p_cxformyuva_fpo_cgelf_start; extern int _binary_p_cxformyuvamul_fpo_cgelf_start; #endif class GRendererOGLImplPS3 : public GRendererOGLImpl { public: int CurVProgram; CGprofile CgFProfile, CgVProfile; CgShader CgFShaders[PS_Count]; CgVProgram CgVShaders[2]; GTextureOGL* CreateTexture() { ReleaseQueuedResources(); GLock::Locker guard(&TexturesLock); return new GTextureOGLImplPS3(this); } GTextureOGL* CreateTextureYUV() { ReleaseQueuedResources(); GLock::Locker guard(&TexturesLock); return new GTextureOGLImplPS3YUV(this); } virtual void DisableShaders () { cgGLDisableProfile (CgFProfile); cgGLDisableProfile (CgVProfile); } virtual void SetPixelShader (PixelShaderType ps, SInt pass = 0) { GUNUSED(pass); CurrentShader = ps; cgGLBindProgram (CgFShaders[ps].prog); cgGLEnableProfile (CgFProfile); } virtual bool SetVertexProgram (VertexFormat vf, SInt numtex) { if (vf == Vertex_XY16iCF32) { CurVProgram = (numtex == 2) ? 1 : 0; cgGLBindProgram (CgVShaders[CurVProgram].prog); cgGLEnableProfile (CgVProfile); return 1; } CurVProgram = 0; return 0; } virtual void SetVertexProgState () { cgGLSetStateMatrixParameter (CgVShaders[CurVProgram].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); } virtual 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]; cgGLSetParameter4fv (CgVShaders[CurVProgram].texgenx[stageIndex], p); p[0] = m.M_[1][0]; p[1] = m.M_[1][1]; p[3] = m.M_[1][2]; cgGLSetParameter4fv (CgVShaders[CurVProgram].texgeny[stageIndex], p); } virtual 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 }; cgGLSetParameter4fv (CgFShaders[CurrentShader].cxmul, scm); cgGLSetParameter4fv (CgFShaders[CurrentShader].cxadd, sca); } virtual void VertexAttribArray (SInt attr, GLint size, GLenum type, GLboolean norm, GLsizei stride, GLvoid* array) { GUNUSED2(attr,norm); cgGLSetParameterPointer (CgVShaders[CurVProgram].factor, size, type, stride, array); //cgGLSetParameterPointer (CgVShaders[CurVProgram].factor, 2, GL_SHORT, stride, array); cgGLEnableClientState (CgVShaders[CurVProgram].factor); } virtual void DisableVertexAttribArrays () { cgGLDisableClientState (CgVShaders[CurVProgram].factor); } void InitFragShader (CGcontext ctx, PixelShaderType ps, const void *progin) { CgFShaders[ps].prog = cgCreateProgram(ctx, CG_BINARY, (const char*) progin, CgFProfile, NULL, NULL); CgFShaders[ps].cxmul = cgGetNamedParameter (CgFShaders[ps].prog, "cmul"); CgFShaders[ps].cxadd = cgGetNamedParameter (CgFShaders[ps].prog, "cadd"); CgFShaders[ps].tex[0] = cgGetNamedParameter (CgFShaders[ps].prog, "tex"); if (!CgFShaders[ps].tex[0]) { CgFShaders[ps].tex[0] = cgGetNamedParameter (CgFShaders[ps].prog, "tex_y"); if (CgFShaders[ps].tex[0]) { CgFShaders[ps].tex[2] = cgGetNamedParameter (CgFShaders[ps].prog, "tex_u"); CgFShaders[ps].tex[3] = cgGetNamedParameter (CgFShaders[ps].prog, "tex_v"); CgFShaders[ps].tex[4] = cgGetNamedParameter (CgFShaders[ps].prog, "tex_a"); } } else CgFShaders[ps].tex[1] = cgGetNamedParameter (CgFShaders[ps].prog, "tex1"); } virtual bool SetDependentVideoMode() { if (!GRendererOGLImpl::SetDependentVideoMode()) return 0; // Already initialized, return if (UseShaders) return 1; CgFProfile = cgGLGetLatestProfile (CG_GL_FRAGMENT); cgGLEnableProfile (CgFProfile); CgVProfile = cgGLGetLatestProfile (CG_GL_VERTEX); cgGLEnableProfile (CgVProfile); CurVProgram = 0; CGcontext ctx = cgCreateContext(); cgGLSetManageTextureParameters (ctx, 1); CgVShaders[0].prog = cgCreateProgram(ctx, CG_BINARY, (const char *) &_binary_v_1tex_vpo_cgelf_start, CgVProfile, NULL, NULL); CgVShaders[0].texgenx[0] = cgGetNamedParameter (CgVShaders[0].prog, "texgenx0"); CgVShaders[0].texgeny[0] = cgGetNamedParameter (CgVShaders[0].prog, "texgeny0"); CgVShaders[0].factor = cgGetNamedParameter (CgVShaders[0].prog, "ifactor"); CgVShaders[0].mvp = cgGetNamedParameter (CgVShaders[0].prog, "mvp"); CgVShaders[1].prog = cgCreateProgram(ctx, CG_BINARY, (const char *) &_binary_v_2tex_vpo_cgelf_start, CgVProfile, NULL, NULL); CgVShaders[1].texgenx[0] = cgGetNamedParameter (CgVShaders[1].prog, "texgenx0"); CgVShaders[1].texgeny[0] = cgGetNamedParameter (CgVShaders[1].prog, "texgeny0"); CgVShaders[1].texgenx[1] = cgGetNamedParameter (CgVShaders[1].prog, "texgenx1"); CgVShaders[1].texgeny[1] = cgGetNamedParameter (CgVShaders[1].prog, "texgeny1"); CgVShaders[1].factor = cgGetNamedParameter (CgVShaders[1].prog, "ifactor"); CgVShaders[1].mvp = cgGetNamedParameter (CgVShaders[1].prog, "mvp"); InitFragShader (ctx, PS_TextTexture, &_binary_p_texta_fpo_cgelf_start); InitFragShader (ctx, PS_TextTextureColor, &_binary_p_text_fpo_cgelf_start); InitFragShader (ctx, PS_TextTextureColorMultiply, &_binary_p_textmul_fpo_cgelf_start); InitFragShader (ctx, PS_TextTextureYUV, &_binary_p_cxformyuv_fpo_cgelf_start); InitFragShader (ctx, PS_TextTextureYUVA, &_binary_p_cxformyuva_fpo_cgelf_start); InitFragShader (ctx, PS_TextTextureYUVMultiply, &_binary_p_cxformyuvmul_fpo_cgelf_start); InitFragShader (ctx, PS_TextTextureYUVAMultiply, &_binary_p_cxformyuvamul_fpo_cgelf_start); InitFragShader (ctx, PS_CxformTexture, &_binary_p_cxform_fpo_cgelf_start); InitFragShader (ctx, PS_CxformTextureMultiply, &_binary_p_cxformmul_fpo_cgelf_start); InitFragShader (ctx, PS_CxformGouraud, &_binary_p_cxg_fpo_cgelf_start); InitFragShader (ctx, PS_CxformGouraudMultiply, &_binary_p_cxgm_fpo_cgelf_start); InitFragShader (ctx, PS_CxformGouraudNoAddAlpha, &_binary_p_cxgna_fpo_cgelf_start); InitFragShader (ctx, PS_CxformGouraudMultiplyNoAddAlpha, &_binary_p_cxgmna_fpo_cgelf_start); InitFragShader (ctx, PS_CxformGouraudTexture, &_binary_p_cxgt_fpo_cgelf_start); InitFragShader (ctx, PS_CxformGouraudMultiplyTexture, &_binary_p_cxgtm_fpo_cgelf_start); InitFragShader (ctx, PS_Cxform2Texture, &_binary_p_cxg2t_fpo_cgelf_start); InitFragShader (ctx, PS_CxformMultiply2Texture, &_binary_p_cxg2tm_fpo_cgelf_start); UseAcBlend = 1; UseShaders = 1; MaxTexUnits = 4; TexNonPower2 = 2; return 1; } }; void GTextureOGLImplPS3::Bind(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps) { GRendererOGLImplPS3 *pRendererPS3 = (GRendererOGLImplPS3*)pRenderer; glActiveTexture(cgGLGetTextureEnum(pRendererPS3->CgFShaders[pRendererPS3->CurrentShader].tex[stageIndex])); glBindTexture(GL_TEXTURE_2D, TextureId); cgGLSetTextureParameter (pRendererPS3->CgFShaders[pRendererPS3->CurrentShader].tex[stageIndex], TextureId); cgGLEnableTextureParameter (pRendererPS3->CgFShaders[pRendererPS3->CurrentShader].tex[stageIndex]); pRenderer->ApplySampleMode(WrapMode, SampleMode, useMipmaps); } void GTextureOGLImplPS3YUV::Bind(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps) { GASSERT(stageIndex == 0); GRendererOGLImplPS3 *pRendererPS3 = (GRendererOGLImplPS3*)pRenderer; for (int i = 0; i < (TextureUVA[2] ? 3 : 2); i++) { glActiveTexture(cgGLGetTextureEnum(pRendererPS3->CgFShaders[pRendererPS3->CurrentShader].tex[i+2])); glBindTexture(GL_TEXTURE_2D, TextureUVA[i]); cgGLSetTextureParameter (pRendererPS3->CgFShaders[pRendererPS3->CurrentShader].tex[i+2], TextureUVA[i]); cgGLEnableTextureParameter (pRendererPS3->CgFShaders[pRendererPS3->CurrentShader].tex[i+2]); pRenderer->ApplySampleMode(WrapMode, SampleMode, useMipmaps); } glActiveTexture(cgGLGetTextureEnum(pRendererPS3->CgFShaders[pRendererPS3->CurrentShader].tex[0])); glBindTexture(GL_TEXTURE_2D, TextureId); cgGLSetTextureParameter (pRendererPS3->CgFShaders[pRendererPS3->CurrentShader].tex[0], TextureId); cgGLEnableTextureParameter (pRendererPS3->CgFShaders[pRendererPS3->CurrentShader].tex[0]); pRenderer->ApplySampleMode(WrapMode, SampleMode, useMipmaps); }