diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 33476d023..b61e709e2 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -175,8 +175,8 @@ const char* VertexShaderSource = //0 - not in use //1 - in use since the last frame -//2 - not anymore in use (e.g. exit to menu) u8 rttInUse = 0; +u32 rttDepthCounter = 0; /* @@ -393,6 +393,10 @@ gl_ctx gl; int screen_width; int screen_height; +bool isExtensionSupported(const char * name) { + return strstr((const char *)glGetString(GL_EXTENSIONS), name) != NULL; +} + #if (HOST_OS != OS_DARWIN) && !defined(TARGET_NACL32) #if defined(GLES) && !defined(USE_SDL) // Create a basic GLES context @@ -1450,7 +1454,7 @@ void OSD_DRAW() bool ProcessFrame(TA_context* ctx) { - if (ctx->rend.isRTT && settings.dreamcast.rttOption == 0) + if (ctx->rend.isRTT && settings.dreamcast.rttOption == Disabled) { return false; } @@ -1582,16 +1586,11 @@ bool RenderFrame() { gcflip=1; - //For some reason this produces wrong results - //so for now its hacked based like on the d3d code - - dc_width = FB_X_CLIP.max - FB_X_CLIP.min + 1; + dc_width = FB_W_LINESTRIDE.stride ? FB_W_LINESTRIDE.stride * 4 : FB_X_CLIP.max - FB_X_CLIP.min + 1; dc_height = FB_Y_CLIP.max - FB_Y_CLIP.min + 1; - //u32 pvr_stride=(FB_W_LINESTRIDE.stride)*8; } float scale_x=1, scale_y=1; - float scissoring_scale_x = 1; if (!is_rtt) @@ -1617,8 +1616,6 @@ bool RenderFrame() dc_width *= scale_x; dc_height *= scale_y; - glUseProgram(gl.modvol_shader.program); - /* float vnear=0; @@ -1646,17 +1643,28 @@ bool RenderFrame() /* Handle Dc to screen scaling */ + float dc2s_scale_h = screen_height / 480.0; + float ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0) / 2; - float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0); - float ds2s_offs_x = is_rtt ? 0 : ((screen_width - dc2s_scale_h * 640.0) / 2); + if (!is_rtt) { + ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x); + ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width; + } else { + if (dc_width == (FB_X_CLIP.max - FB_X_CLIP.min + 1)) { + ShaderUniforms.scale_coefs[0] = 2.0f / (dc_width * scale_x); + } + else { //is stride + ShaderUniforms.scale_coefs[0] = 2.0f / ((FB_X_CLIP.max - FB_X_CLIP.min + 1) * scale_x); + } + dc2s_scale_h = screen_width / dc_width; + ds2s_offs_x = 0; + ShaderUniforms.scale_coefs[2] = 1; + } //-1 -> too much to left - ShaderUniforms.scale_coefs[0]=2.0f/(screen_width/dc2s_scale_h*scale_x); ShaderUniforms.scale_coefs[1]=(is_rtt?2:-2)/dc_height; - ShaderUniforms.scale_coefs[2]=1-2*ds2s_offs_x/(screen_width); ShaderUniforms.scale_coefs[3]=(is_rtt?1:-1); - ShaderUniforms.depth_coefs[0]=2/(vtx_max_fZ-vtx_min_fZ); ShaderUniforms.depth_coefs[1]=-vtx_min_fZ-1; ShaderUniforms.depth_coefs[2]=0; @@ -1664,7 +1672,6 @@ bool RenderFrame() //printf("scale: %f, %f, %f, %f\n",scale_coefs[0],scale_coefs[1],scale_coefs[2],scale_coefs[3]); - //VERT and RAM fog color constants u8* fog_colvert_bgra=(u8*)&FOG_COL_VERT; u8* fog_colram_bgra=(u8*)&FOG_COL_RAM; @@ -1722,6 +1729,7 @@ bool RenderFrame() ShaderUniforms.Set(s); } + //setup render target first if (is_rtt) { @@ -1740,7 +1748,7 @@ bool RenderFrame() case 2: //0x2 4444 ARGB 16 bit channels=GL_RGBA; - format=GL_UNSIGNED_SHORT_5_5_5_1; + format=GL_UNSIGNED_SHORT_4_4_4_4; break; case 3://0x3 1555 ARGB 16 bit The alpha value is determined by comparison with the value of fb_alpha_threshold. @@ -1749,38 +1757,28 @@ bool RenderFrame() break; case 4: //0x4 888 RGB 24 bit packed - channels=GL_RGB; - format=GL_UNSIGNED_SHORT_5_6_5; - break; - case 5: //0x5 0888 KRGB 32 bit K is the value of fk_kval. - channels=GL_RGBA; - format=GL_UNSIGNED_SHORT_4_4_4_4; - break; - case 6: //0x6 8888 ARGB 32 bit - channels=GL_RGBA; - format=GL_UNSIGNED_SHORT_4_4_4_4; - break; - case 7: //7 invalid - die("7 is not valid"); - break; + default: + die("Not supported RTT format"); + return false; } - BindRTT(FB_W_SOF1&VRAM_MASK,FB_X_CLIP.max-FB_X_CLIP.min+1,FB_Y_CLIP.max-FB_Y_CLIP.min+1,channels,format); + + if (rttInUse == 1) { + rttDepthCounter++; + } + BindRTT(FB_W_SOF1 & VRAM_MASK, dc_width, dc_height, channels, format); rttInUse = 1; } else { #if HOST_OS != OS_DARWIN - if (rttInUse == 1) { - ReadRTT(); - rttInUse = 2; - } - else if (rttInUse == 2) { - FreeRTTBuffers(); - rttInUse = 0; - } + if (rttInUse == 1) { + ReadRTT(); + rttInUse = 0; + } + rttDepthCounter = 0; glBindFramebuffer(GL_FRAMEBUFFER,0); glViewport(0, 0, screen_width, screen_height); @@ -1840,12 +1838,12 @@ bool RenderFrame() else glEnable(GL_SCISSOR_TEST); - //restore scale_x scale_x /= scissoring_scale_x; - if (!(is_rtt && (settings.dreamcast.rttOption > 0 && settings.dreamcast.rttOption <= 3))) + if (!(is_rtt && (settings.dreamcast.rttOption > Disabled && settings.dreamcast.rttOption <= ShadowCircle))) { + checkIfUpdated(); DrawStrips(); } diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index 02e28d072..fae84a68f 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -43,9 +43,21 @@ //vertex types extern u32 gcflip; +extern u32 rttDepthCounter; +extern bool isExtensionSupported(const char *); + +enum rttSelectedOption +{ + Disabled = 0, + Zeros, + Ones, + ShadowCircle, + Full +}; void DrawStrips(); +void checkIfUpdated(); struct PipelineShader { @@ -118,7 +130,6 @@ void SortPParams(); void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt); void ReadRTT(); -void FreeRTTBuffers(); int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode, u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset, u32 pp_FogCtrl); diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 880c1d97a..6a7f3952c 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -1,7 +1,9 @@ #include "gles.h" #include "rend/TexCache.h" #include "hw/pvr/pvr_mem.h" -#include +#include +#include +#include #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -28,7 +30,7 @@ Compression const u32 shadowCircleW = 128; const u32 shadowCircleH = 128; u16 shadowCircleTexture[shadowCircleW][shadowCircleH] = {0}; -u16 buf[1024*1024]; +set delayedUpdateQueue; #if FEAT_HAS_SOFTREND #include @@ -148,7 +150,7 @@ struct TextureCacheData else { texID = 0; } - + pData = 0; tex_type = 0; @@ -232,7 +234,7 @@ struct TextureCacheData verify(tcw.VQ_Comp==0); //Planar textures support stride selection, mostly used for non power of 2 textures (videos) int stride=w; - if (tcw.StrideSel) + if (tcw.StrideSel) stride=(TEXT_CONTROL&31)*32; //Call the format specific conversion code texconv=tex->PL; @@ -270,8 +272,12 @@ struct TextureCacheData } } - void Update() + void Update(bool isSourceVram = true, u16 *sourceData = NULL) { + if (!isSourceVram && !sourceData) { + return; + } + //texture state tracking stuff Updates++; dirty=0; @@ -284,13 +290,13 @@ struct TextureCacheData pal_local_rev=*pal_table_rev; //make sure to update the local rev, so it won't have to redo the tex } - palette_index=indirect_color_ptr; //might be used if pal. tex - vq_codebook=(u8*)&vram[indirect_color_ptr]; //might be used if VQ tex + palette_index = indirect_color_ptr; //might be used if pal. tex + vq_codebook = (u8 *) &vram[indirect_color_ptr]; //might be used if VQ tex //texture conversion work PixelBuffer pbt; pbt.p_buffer_start=pbt.p_current_line=temp_tex_buffer; - pbt.pixels_per_line=w; + u32 stride=w; @@ -299,7 +305,15 @@ struct TextureCacheData if(texconv!=0) { - texconv(&pbt,(u8*)&vram[sa],stride,h); + if (isSourceVram) { + pbt.pixels_per_line = w; + texconv(&pbt, (u8*)&vram[sa], stride, h); + } + else + { + pbt.pixels_per_line = stride; + texconv(&pbt, (u8*)sourceData, stride, h); + } } else { @@ -311,13 +325,19 @@ struct TextureCacheData //PrintTextureName(); //lock the texture to detect changes in it - lock_block = libCore_vramlock_Lock(sa_tex,sa+size-1,this); + if (isSourceVram) { + lock_block = libCore_vramlock_Lock(sa_tex, sa + size - 1, this); + } if (texID) { - //upload to OpenGL ! glBindTexture(GL_TEXTURE_2D, texID); - GLuint comps=textype==GL_UNSIGNED_SHORT_5_6_5?GL_RGB:GL_RGBA; - glTexImage2D(GL_TEXTURE_2D, 0,comps , w, h, 0, comps, textype, temp_tex_buffer); + GLuint comps=textype == GL_UNSIGNED_SHORT_5_6_5 ? GL_RGB : GL_RGBA; + + if (isSourceVram) { + glTexImage2D(GL_TEXTURE_2D, 0, comps, w, h, 0, comps, textype, temp_tex_buffer); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, comps, stride, h, 0, comps, textype, temp_tex_buffer); + } if (tcw.MipMapped && settings.rend.UseMipmaps) glGenerateMipmap(GL_TEXTURE_2D); } @@ -374,7 +394,6 @@ struct TextureCacheData } }; -#include map TexCache; typedef map::iterator TexCacheIter; @@ -382,183 +401,302 @@ typedef map::iterator TexCacheIter; struct FBT { - u32 TexAddr; - GLuint depthb,stencilb; + u32 texAddress; + u16 texData[1024*1024]; + GLuint depthb; GLuint tex; + GLuint renderTex; GLuint fbo; + u32 w; + u32 h; + TextureCacheData tf; + u32 kval_bit; + u32 fb_alpha_threshold; + u32 fb_packmode; + bool texDataValid; + bool updated; + bool initialized; + + FBT(): initialized(false), updated(false), tf({0}), tex(0), renderTex(0), texDataValid(false) {} }; -FBT fb_rtt; - -void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) -{ - FBT& rv=fb_rtt; - - rv.TexAddr=addy>>3; - - // Find the largest square power of two texture that fits into the viewport - - // Get the currently bound frame buffer object. On most platforms this just gives 0. - //glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_i32OriginalFbo); - - // Generate and bind a render buffer which will become a depth buffer shared between our two FBOs - if (!rv.depthb) - glGenRenderbuffers(1, &rv.depthb); - glBindRenderbuffer(GL_RENDERBUFFER, rv.depthb); - - /* - Currently it is unknown to GL that we want our new render buffer to be a depth buffer. - glRenderbufferStorage will fix this and in this case will allocate a depth buffer - m_i32TexSize by m_i32TexSize. - */ - -#ifdef GLES - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, fbw, fbh); -#else - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbw, fbh); -#endif - - if (!rv.stencilb) - glGenRenderbuffers(1, &rv.stencilb); - glBindRenderbuffer(GL_RENDERBUFFER, rv.stencilb); - glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fbw, fbh); - - // Create a texture for rendering to - if (!rv.tex) - glGenTextures(1, &rv.tex); - glBindTexture(GL_TEXTURE_2D, rv.tex); - glTexImage2D(GL_TEXTURE_2D, 0, channels, fbw, fbh, 0, channels, fmt, 0); - +void createTexture(u32 w, u32 h, u32 format, u32 type, GLuint & textureID) { + glGenTextures(1, &textureID); + glBindTexture(GL_TEXTURE_2D, textureID); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, type, 0); +} + +map renderedTextures; + +void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) +{ + FBT *renderedTexture; + u32 location = addy >> 3; + map::iterator iter = renderedTextures.find(location); + + if (iter != renderedTextures.end()) { + renderedTexture = &iter->second; + } + else { + renderedTexture = &renderedTextures[location]; + } + + renderedTexture->texAddress = location; + renderedTexture->fb_packmode = FB_W_CTRL.fb_packmode; + renderedTexture->updated = true; + renderedTexture->texDataValid = false; + renderedTexture->kval_bit = (FB_W_CTRL.fb_kval & 0x80) >> 7; + renderedTexture->fb_alpha_threshold = FB_W_CTRL.fb_alpha_threshold; + renderedTexture->w = fbw; + renderedTexture->h = fbh; + + if (!renderedTexture->tex) { + createTexture(fbw, fbh, channels, fmt, renderedTexture->tex); + } + + //if 'full RTT' is disabled we can return here + if (settings.dreamcast.rttOption != Full) { + return; + } + + // Generate and bind a render buffer which will become a depth buffer + if (!renderedTexture->depthb) { + glGenRenderbuffers(1, &renderedTexture->depthb); + glBindRenderbuffer(GL_RENDERBUFFER, renderedTexture->depthb); + + /* + Currently it is unknown to GL that we want our new render buffer to be a depth buffer. + glRenderbufferStorage will fix this and in this case will allocate a depth buffer + m_i32TexSize by m_i32TexSize. + */ + +#ifdef GLES + if (isExtensionSupported("GL_OES_depth24")) { + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, fbw, fbh); + } + else { + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, fbw, fbh); + } +#else + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbw, fbh); +#endif + } + + // Create a texture for rendering to - may be a color render buffer as well + if (!renderedTexture->renderTex) { + createTexture(fbw, fbh, channels, fmt, renderedTexture->renderTex); + } // Create the object that will allow us to render to the aforementioned texture - if (!rv.fbo) - glGenFramebuffers(1, &rv.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rv.fbo); + if (!renderedTexture->fbo) { + glGenFramebuffers(1, &renderedTexture->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, renderedTexture->fbo); - // Attach the texture to the FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rv.tex, 0); + // Attach the texture to the FBO + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture->renderTex, 0); - // Attach the depth buffer we created earlier to our FBO. - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rv.depthb); + // Attach the depth buffer we created earlier to our FBO. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->depthb); - // Check that our FBO creation was successful - GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); + // Check that our FBO creation was successful + GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - verify(uStatus == GL_FRAMEBUFFER_COMPLETE); + verify(uStatus == GL_FRAMEBUFFER_COMPLETE); + } + else { + glBindFramebuffer(GL_FRAMEBUFFER, renderedTexture->fbo); + } glViewport(0, 0, fbw, fbh); } -void handlePackModeRTT(GLint w, GLint h) +void handlePackModeRTT(GLint w, GLint h, FBT& fbt) { - switch (FB_W_CTRL.fb_packmode) { - //currently RGB 565 is supported only - case 1: //0x1 565 RGB 16 bit - { - u16 *dataPointer = temp_tex_buffer; - glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, temp_tex_buffer); + u16 *dataPointer = fbt.texData; + const u32 kval_upper_bit = fbt.kval_bit; + const u32 fb_alpha_threshold = fbt.fb_alpha_threshold; + + switch (fbt.fb_packmode) { + case 0: //0x0 0555 KRGB 16 bit (default) Bit 15 is the value of fb_kval[7]. + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, fbt.texData); + // convert RGBA5551 to KRGB1555 for (u32 i = 0; i < w * h; i++) { - buf[i] = ((*dataPointer & 0xF000) >> 12) | ((*dataPointer & 0x0FFF) << 4); + fbt.texData[i] = (kval_upper_bit << 15) | ((*dataPointer & 0xFFFE) >> 1); *dataPointer++; } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, buf); - break; - } + + case 1: //0x1 565 RGB 16 bit + glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fbt.texData); + break; + + case 2: //0x2 4444 ARGB 16 bit + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, fbt.texData); + // convert RGBA4444 to ARGB4444 + for (u32 i = 0; i < w * h; i++) + { + fbt.texData[i] = ((*dataPointer & 0x000F) << 12) | ((*dataPointer & 0xFFF0) >> 4); + *dataPointer++; + } + break; + + case 3: //0x3 1555 ARGB 16 bit The alpha value is determined by comparison with the value of fb_alpha_threshold. + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, fbt.texData); + // convert RGBA5551 to ARGB1555 + for (u32 i = 0; i < w * h; i++) + { + // value has 1-bit precision only (RGBA5551), where fb_alpha_threshold is 8-bit + const u16 alpha = (*dataPointer & 0x0001) >= fb_alpha_threshold ? 1 : 0; + fbt.texData[i] = (alpha << 15) | ((*dataPointer & 0xFFFE) >> 1); + *dataPointer++; + } + break; + default: //clear unsupported texture to avoid artifacts - memset(buf, '\0', w * h); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, buf); - + memset(temp_tex_buffer, '\0', w * h); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, temp_tex_buffer); break; } } void ReadRTT() { - FBT& rv=fb_rtt; + map::iterator it; - //get viewport width and height from rtt framebuffer - GLint dimensions[4] = {0}; - glGetIntegerv(GL_VIEWPORT, dimensions); - GLint w = dimensions[2]; - GLint h = dimensions[3]; - - //bind texture to which we have rendered in the last rtt pass - glBindTexture(GL_TEXTURE_2D, rv.tex); - - if (settings.dreamcast.rttOption == 3) + for ( it = renderedTextures.begin(); it != renderedTextures.end(); it++ ) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadowCircleW, shadowCircleH, 0, - GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, shadowCircleTexture[0]); - } - else if (settings.dreamcast.rttOption == 2) - { - for (u32 i = 0; i < w * h; i++) - buf[i] = ~0; + if(!it->second.updated) { + continue; + } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, buf); - } - else if (settings.dreamcast.rttOption == 1) - { - for (u32 i = 0; i < w * h; i++) - buf[i] = 0; + GLint w = it->second.w; + GLint h = it->second.h; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, buf); - } - else if (settings.dreamcast.rttOption == 4) - { - handlePackModeRTT(w, h); + if (settings.dreamcast.rttOption == ShadowCircle) + { + glBindTexture(GL_TEXTURE_2D, it->second.tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadowCircleW, shadowCircleH, 0, + GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, shadowCircleTexture[0]); + it->second.updated = false; + } + else if (settings.dreamcast.rttOption == Ones) + { + for (u32 i = 0; i < w * h; i++) + temp_tex_buffer[i] = (u16)~0; + + glBindTexture(GL_TEXTURE_2D, it->second.tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, temp_tex_buffer); + it->second.updated = false; + } + else if (settings.dreamcast.rttOption == Zeros) + { + for (u32 i = 0; i < w * h; i++) + temp_tex_buffer[i] = 0; + + glBindTexture(GL_TEXTURE_2D, it->second.tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, temp_tex_buffer); + it->second.updated = false; + } + else if (settings.dreamcast.rttOption == Full) + { + glBindFramebuffer(GL_FRAMEBUFFER, it->second.fbo); + if (!it->second.texDataValid) { + handlePackModeRTT(w, h, it->second); + } + it->second.texDataValid = true; + } } } -void FreeRTTBuffers() -{ - if (fb_rtt.fbo) { glDeleteFramebuffers(1,&fb_rtt.fbo); fb_rtt.fbo = 0; } - if (fb_rtt.tex) { glDeleteTextures(1,&fb_rtt.tex); fb_rtt.tex = 0; } - if (fb_rtt.depthb) { glDeleteRenderbuffers(1,&fb_rtt.depthb); fb_rtt.depthb = 0; } - if (fb_rtt.stencilb) { glDeleteRenderbuffers(1,&fb_rtt.stencilb); fb_rtt.stencilb = 0; } +void checkIfUpdated() { + if(!pvrrc.isRTT && delayedUpdateQueue.size()) + { + for (set::iterator it=delayedUpdateQueue.begin(); it != delayedUpdateQueue.end(); ++it) { + //We can directly read because this address exists already + if(renderedTextures[*it].initialized && renderedTextures[*it].updated) + { + renderedTextures[*it].tf.Update(false, renderedTextures[*it].texData); + renderedTextures[*it].updated = false; + } + } + delayedUpdateQueue.clear(); + } } -GLuint gl_GetTexture(TSP tsp, TCW tcw) -{ - if (tcw.TexAddr==fb_rtt.TexAddr && fb_rtt.tex) +void initializeRttTexture(const TSP & tsp, const TCW & tcw, FBT * tempRenderedTexture) { + if (!tempRenderedTexture->initialized) { - return fb_rtt.tex; + tempRenderedTexture->tf.tsp = tsp; + tempRenderedTexture->tf.tcw = tcw; + tempRenderedTexture->tf.Create(false); + tempRenderedTexture->tf.texID = tempRenderedTexture->tex; + for (u32 i = 0; i < sizeof(tempRenderedTexture->texData)/sizeof(tempRenderedTexture->texData[0]); ++i) { + tempRenderedTexture->texData[i] = 0; + } + tempRenderedTexture->initialized = true; + } +} + +GLuint gl_GetTexture(TSP tsp, TCW tcw) { + + FBT* tempRenderedTexture = NULL; + map::iterator it = renderedTextures.find(tcw.TexAddr); + if (it != renderedTextures.end()) { + tempRenderedTexture = &it->second; + } + + if (tempRenderedTexture && tcw.TexAddr == tempRenderedTexture->texAddress) { + //create for the first time + initializeRttTexture(tsp, tcw, tempRenderedTexture); + + //if there was no update, it is not an RTT frame (BindRTT was not invoked) then proceed the standard way + if (tempRenderedTexture->tf.tcw.full == tcw.full) + { + if (tempRenderedTexture->updated) + { + delayedUpdateQueue.insert(tcw.TexAddr); + tempRenderedTexture->tf.tsp = tsp; + tempRenderedTexture->tf.Create(false); + tempRenderedTexture->tf.texID = tempRenderedTexture->tex; + } + return tempRenderedTexture->tex; + } } //lookup texture - TextureCacheData* tf; + TextureCacheData *tf; //= TexCache.Find(tcw.full,tsp.full); - u64 key=((u64)tcw.full<<32) | tsp.full; + u64 key = ((u64) tcw.full << 32) | tsp.full; - TexCacheIter tx=TexCache.find(key); + TexCacheIter tx = TexCache.find(key); - if (tx!=TexCache.end()) - { - tf=&tx->second; + if (tx != TexCache.end()) { + tf = &tx->second; } else //create if not existing { - TextureCacheData tfc={0}; - TexCache[key]=tfc; + TextureCacheData tfc = {0}; + TexCache[key] = tfc; - tx=TexCache.find(key); - tf=&tx->second; + tx = TexCache.find(key); + tf = &tx->second; + + tf->tsp = tsp; + tf->tcw = tcw; - tf->tsp=tsp; - tf->tcw=tcw; tf->Create(true); } //update if needed - if (tf->NeedsUpdate()) + if (tf->NeedsUpdate()) { tf->Update(); + } //update state for opts/stuff tf->Lookups++; @@ -567,7 +705,6 @@ GLuint gl_GetTexture(TSP tsp, TCW tcw) return tf->texID; } - text_info raw_GetTexture(TSP tsp, TCW tcw) { text_info rv = { 0 }; @@ -609,7 +746,6 @@ text_info raw_GetTexture(TSP tsp, TCW tcw) rv.pdata = tf->pData; rv.textype = tf->tex_type; - return rv; } @@ -631,7 +767,6 @@ void CollectCleanup() { for (size_t i=0; i