From f309a59fac091729c1951cb036c166f21c1b0b1f Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 28 Oct 2018 20:16:45 +0100 Subject: [PATCH 01/22] Render to texture single pass implemented --- core/hw/pvr/ta_ctx.cpp | 5 ++- core/rend/gles/gldraw.cpp | 21 +++++----- core/rend/gles/gles.cpp | 40 ++++++++++--------- core/rend/gles/gles.h | 2 + core/rend/gles/gltex.cpp | 81 ++++++++++++++++++++++++++++++--------- 5 files changed, 101 insertions(+), 48 deletions(-) diff --git a/core/hw/pvr/ta_ctx.cpp b/core/hw/pvr/ta_ctx.cpp index f7a3b736c..fdf3fd9eb 100644 --- a/core/hw/pvr/ta_ctx.cpp +++ b/core/hw/pvr/ta_ctx.cpp @@ -146,14 +146,15 @@ bool QueueRender(TA_context* ctx) bool too_fast = (cycle_span / time_span) > (SH4_MAIN_CLOCK * 1.2); - if (rqueue && too_fast && settings.pvr.SynchronousRender) { + if ((rqueue && too_fast && settings.pvr.SynchronousRender) || + (rqueue && ctx->rend.isRTT)) { //wait for a frame if // we have another one queue'd and // sh4 run at > 120% on the last slice // and SynchronousRendering is enabled frame_finished.Wait(); verify(!rqueue); - } + } if (rqueue) { tactx_Recycle(ctx); diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index ded55e1d4..f2a37fecd 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -146,15 +146,18 @@ s32 SetTileClip(u32 val, bool set) return 0; if (set && clip_mode) { - csy = 480 - csy; - cey = 480 - cey; - float dc2s_scale_h = screen_height / 480.0f; - float ds2s_offs_x = (screen_width - dc2s_scale_h * 640) / 2; - csx = csx * dc2s_scale_h + ds2s_offs_x; - cex = cex * dc2s_scale_h + ds2s_offs_x; - csy = csy * dc2s_scale_h; - cey = cey * dc2s_scale_h; - glUniform4f(CurrentShader->pp_ClipTest, csx, cey, cex, csy); + if (!pvrrc.isRTT) { + float t = cey; + cey = 480 - csy; + csy = 480 - t; + float dc2s_scale_h = screen_height / 480.0f; + float ds2s_offs_x = (screen_width - dc2s_scale_h * 640) / 2; + csx = csx * dc2s_scale_h + ds2s_offs_x; + cex = cex * dc2s_scale_h + ds2s_offs_x; + csy = csy * dc2s_scale_h; + cey = cey * dc2s_scale_h; + } + glUniform4f(CurrentShader->pp_ClipTest, csx, csy, cex, cey); } return clip_mode; diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index d8ec2823f..e7bb861c4 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -172,10 +172,10 @@ const char* VertexShaderSource = #endif - - - - +//0 - not in use +//1 - in use since the last frame +//2 - not anymore in use (e.g. exit to menu) +u8 rttInUse = 0; /* @@ -1447,10 +1447,6 @@ void OSD_DRAW() bool ProcessFrame(TA_context* ctx) { - //disable RTTs for now .. - if (ctx->rend.isRTT) - return false; - ctx->rend_inuse.Lock(); ctx->MarkRend(); @@ -1580,14 +1576,10 @@ bool RenderFrame() //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_height=FB_Y_CLIP.max-FB_Y_CLIP.min+1; - u32 pvr_stride=(FB_W_LINESTRIDE.stride)*8; - */ - dc_width=640; - dc_height=480; + dc_width = 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; @@ -1646,8 +1638,9 @@ bool RenderFrame() /* Handle Dc to screen scaling */ - float dc2s_scale_h=screen_height/480.0f; - float ds2s_offs_x=(screen_width-dc2s_scale_h*640)/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); //-1 -> too much to left ShaderUniforms.scale_coefs[0]=2.0f/(screen_width/dc2s_scale_h*scale_x); @@ -1703,7 +1696,6 @@ bool RenderFrame() glUniform4fv( gl.modvol_shader.scale, 1, ShaderUniforms.scale_coefs); glUniform4fv( gl.modvol_shader.depth_scale, 1, ShaderUniforms.depth_coefs); - GLfloat td[4]={0.5,0,0,0}; glUseProgram(gl.OSD_SHADER.program); @@ -1768,12 +1760,22 @@ bool RenderFrame() break; } 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); + rttInUse = 1; } else { #if HOST_OS != OS_DARWIN - //Fix this in a proper way + if (rttInUse == 1) { + ReadRTT(); + rttInUse = 2; + } + else if (rttInUse == 2) { + FreeRTTBuffers(); + rttInUse = 0; + } + glBindFramebuffer(GL_FRAMEBUFFER,0); + glViewport(0, 0, screen_width, screen_height); #endif } diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index c77e67f5b..63b841d6a 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -117,6 +117,8 @@ void DoCleanup(); 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 171c6897b..6399ce1aa 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -20,6 +20,8 @@ Compression look into it, but afaik PVRC is not realtime doable */ +u16 buf[1024*1024]; + #if FEAT_HAS_SOFTREND #include #endif @@ -384,11 +386,6 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) { FBT& rv=fb_rtt; - if (rv.fbo) glDeleteFramebuffers(1,&rv.fbo); - if (rv.tex) glDeleteTextures(1,&rv.tex); - if (rv.depthb) glDeleteRenderbuffers(1,&rv.depthb); - if (rv.stencilb) glDeleteRenderbuffers(1,&rv.stencilb); - rv.TexAddr=addy>>3; // Find the largest square power of two texture that fits into the viewport @@ -397,7 +394,8 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) //glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_i32OriginalFbo); // Generate and bind a render buffer which will become a depth buffer shared between our two FBOs - glGenRenderbuffers(1, &rv.depthb); + if (!rv.depthb) + glGenRenderbuffers(1, &rv.depthb); glBindRenderbuffer(GL_RENDERBUFFER, rv.depthb); /* @@ -412,23 +410,25 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbw, fbh); #endif - glGenRenderbuffers(1, &rv.stencilb); + 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 - glGenTextures(1, &rv.tex); + 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); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_OES); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_OES); // Create the object that will allow us to render to the aforementioned texture - glGenFramebuffers(1, &rv.fbo); + if (!rv.fbo) + glGenFramebuffers(1, &rv.fbo); glBindFramebuffer(GL_FRAMEBUFFER, rv.fbo); // Attach the texture to the FBO @@ -441,6 +441,51 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); verify(uStatus == GL_FRAMEBUFFER_COMPLETE); + + glViewport(0, 0, fbw, fbh); +} + +void ReadRTT() { + FBT& rv=fb_rtt; + + //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); + + 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); + for (u32 i = 0; i < w * h; i++) { + buf[i] = ((*dataPointer & 0xF000) >> 12) | ((*dataPointer & 0x0FFF) << 4); + *dataPointer++; + } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, buf); + + 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); + + break; + } +} + +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; } } GLuint gl_GetTexture(TSP tsp, TCW tcw) @@ -523,12 +568,12 @@ text_info raw_GetTexture(TSP tsp, TCW tcw) //return gl texture rv.height = tf->h; - rv.width = tf->w; - rv.pdata = tf->pData; - rv.textype = tf->tex_type; - - - return rv; + rv.width = tf->w; + rv.pdata = tf->pData; + rv.textype = tf->tex_type; + + + return rv; } void CollectCleanup() { From 4fd9de54cee25d52777b5bf6b66c01703c5b971c Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 11 Nov 2018 15:28:39 +0100 Subject: [PATCH 02/22] Added rtt menu options --- core/nullDC.cpp | 2 ++ core/rend/gles/gles.cpp | 3 ++ core/types.h | 1 + .../java/com/reicast/emulator/Emulator.java | 4 +++ .../emulator/config/OptionsFragment.java | 20 +++++++++++++ .../java/com/reicast/emulator/emu/JNIdc.java | 1 + .../reicast/src/main/jni/src/Android.cpp | 7 +++++ .../res/layout-v14/configure_fragment.xml | 29 +++++++++++++++++++ .../main/res/layout/configure_fragment.xml | 29 +++++++++++++++++++ .../src/main/res/values-pl/strings.xml | 1 + .../src/main/res/values-ru/strings.xml | 1 + .../src/main/res/values/donottranslate.xml | 8 +++++ .../reicast/src/main/res/values/strings.xml | 1 + 13 files changed, 107 insertions(+) diff --git a/core/nullDC.cpp b/core/nullDC.cpp index 00309250c..e70d9220a 100755 --- a/core/nullDC.cpp +++ b/core/nullDC.cpp @@ -294,6 +294,7 @@ void LoadSettings() settings.dreamcast.RTC = cfgLoadInt("config", "Dreamcast.RTC", GetRTC_now()); settings.dreamcast.region = cfgLoadInt("config", "Dreamcast.Region", 3); settings.dreamcast.broadcast = cfgLoadInt("config", "Dreamcast.Broadcast", 4); + settings.dreamcast.rttOption = cfgLoadInt("config", "Dreamcast.Rtt", 0); settings.aica.LimitFPS = cfgLoadInt("config", "aica.LimitFPS", 1); settings.aica.NoBatch = cfgLoadInt("config", "aica.NoBatch", 0); settings.aica.NoSound = cfgLoadInt("config", "aica.NoSound", 0); @@ -377,4 +378,5 @@ void SaveSettings() cfgSaveInt("config","Dreamcast.RTC", settings.dreamcast.RTC); cfgSaveInt("config","Dreamcast.Region", settings.dreamcast.region); cfgSaveInt("config","Dreamcast.Broadcast", settings.dreamcast.broadcast); + cfgSaveInt("config","Dreamcast.Rtt", settings.dreamcast.rttOption); } diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index e7bb861c4..f978e698a 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -1,4 +1,5 @@ #include +#include #include "gles.h" #include "rend/TexCache.h" #include "cfg/cfg.h" @@ -1779,6 +1780,8 @@ bool RenderFrame() #endif } + printf("RTT option: %d", settings.dreamcast.rttOption); + //Clear depth //Color is cleared by the bgp if (settings.rend.WideScreen) diff --git a/core/types.h b/core/types.h index dadb01cab..bc91bea78 100644 --- a/core/types.h +++ b/core/types.h @@ -640,6 +640,7 @@ struct settings_t u32 RTC; u32 region; u32 broadcast; + u32 rttOption; } dreamcast; struct diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/Emulator.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/Emulator.java index 1f005bb76..52c555b53 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/Emulator.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/Emulator.java @@ -16,6 +16,7 @@ public class Emulator extends Application { public static final String pref_cable = "dc_cable"; public static final String pref_dcregion = "dc_region"; public static final String pref_broadcast = "dc_broadcast"; + public static final String pref_rtt = "dc_rtt"; public static final String pref_limitfps = "limit_fps"; public static final String pref_nosound = "sound_disabled"; public static final String pref_mipmaps = "use_mipmaps"; @@ -34,6 +35,7 @@ public class Emulator extends Application { public static int cable = 3; public static int dcregion = 3; public static int broadcast = 4; + public static int rtt = 3; public static boolean limitfps = true; public static boolean nobatch = false; public static boolean nosound = false; @@ -57,6 +59,7 @@ public class Emulator extends Application { Emulator.cable = mPrefs.getInt(pref_cable, cable); Emulator.dcregion = mPrefs.getInt(pref_dcregion, dcregion); Emulator.broadcast = mPrefs.getInt(pref_broadcast, broadcast); + Emulator.rtt = mPrefs.getInt(pref_rtt, rtt); Emulator.limitfps = mPrefs.getBoolean(pref_limitfps, limitfps); Emulator.nosound = mPrefs.getBoolean(pref_nosound, nosound); Emulator.mipmaps = mPrefs.getBoolean(pref_mipmaps, mipmaps); @@ -80,6 +83,7 @@ public class Emulator extends Application { JNIdc.cable(Emulator.cable); JNIdc.region(Emulator.dcregion); JNIdc.broadcast(Emulator.broadcast); + JNIdc.rtt(Emulator.rtt); JNIdc.limitfps(Emulator.limitfps ? 1 : 0); JNIdc.nobatch(Emulator.nobatch ? 1 : 0); JNIdc.nosound(Emulator.nosound ? 1 : 0); diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java index c5e4c40ed..07e2d1c84 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java @@ -378,6 +378,24 @@ public class OptionsFragment extends Fragment { } }); + //---------------------------------------- + String[] rtts = getResources().getStringArray(R.array.rtt); + Spinner rtt_spnr = (Spinner) getView().findViewById(R.id.rtt_spinner); + ArrayAdapter rttAdapter = new ArrayAdapter<>( + getActivity(), R.layout.spinner_selected, rtts); + rttAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + rtt_spnr.setAdapter(rttAdapter); + rtt_spnr.setSelection(mPrefs.getInt(Emulator.pref_rtt, Emulator.rtt), true); + rtt_spnr.setOnItemSelectedListener(new OnItemSelectedListener() { + public void onItemSelected(AdapterView parent, View view, int pos, long id) { + mPrefs.edit().putInt(Emulator.pref_rtt, pos).apply(); + } + + public void onNothingSelected(AdapterView arg0) { + } + }); +//---------------------------------------- + OnCheckedChangeListener limitfps_option = new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { @@ -711,6 +729,7 @@ public class OptionsFragment extends Fragment { mPrefs.edit().remove(Emulator.pref_cable).apply(); mPrefs.edit().remove(Emulator.pref_dcregion).apply(); mPrefs.edit().remove(Emulator.pref_broadcast).apply(); + mPrefs.edit().remove(Emulator.pref_rtt).apply(); mPrefs.edit().remove(Emulator.pref_limitfps).apply(); mPrefs.edit().remove(Emulator.pref_mipmaps).apply(); mPrefs.edit().remove(Emulator.pref_widescreen).apply(); @@ -730,6 +749,7 @@ public class OptionsFragment extends Fragment { Emulator.cable = 3; Emulator.dcregion = 3; Emulator.broadcast = 4; + Emulator.rtt = 3; Emulator.limitfps = true; Emulator.mipmaps = true; Emulator.widescreen = false; diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java index ec8c5604c..d6327069a 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java @@ -36,6 +36,7 @@ public final class JNIdc public static native void cable(int cable); public static native void region(int region); public static native void broadcast(int broadcast); + public static native void rtt(int rtt); public static native void limitfps(int limiter); public static native void nobatch(int nobatch); public static native void nosound(int noaudio); diff --git a/shell/android-studio/reicast/src/main/jni/src/Android.cpp b/shell/android-studio/reicast/src/main/jni/src/Android.cpp index de4ef695f..deccebceb 100644 --- a/shell/android-studio/reicast/src/main/jni/src/Android.cpp +++ b/shell/android-studio/reicast/src/main/jni/src/Android.cpp @@ -52,6 +52,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_safemode(JNIEnv *env, JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_cable(JNIEnv *env,jobject obj, jint cable) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_region(JNIEnv *env,jobject obj, jint region) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_broadcast(JNIEnv *env,jobject obj, jint broadcast) __attribute__((visibility("default"))); +JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rtt(JNIEnv *env,jobject obj, jint rtt) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_limitfps(JNIEnv *env,jobject obj, jint limiter) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_nobatch(JNIEnv *env,jobject obj, jint nobatch) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_nosound(JNIEnv *env,jobject obj, jint noaudio) __attribute__((visibility("default"))); @@ -102,6 +103,12 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_broadcast(JNIEnv *env settings.dreamcast.broadcast = broadcast; } +JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rtt(JNIEnv *env,jobject obj, jint rtt) +{ + settings.dreamcast.rttOption = rtt; +} + + JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_limitfps(JNIEnv *env,jobject obj, jint limiter) { settings.aica.LimitFPS = limiter; diff --git a/shell/android-studio/reicast/src/main/res/layout-v14/configure_fragment.xml b/shell/android-studio/reicast/src/main/res/layout-v14/configure_fragment.xml index 866364961..ffa7f2566 100644 --- a/shell/android-studio/reicast/src/main/res/layout-v14/configure_fragment.xml +++ b/shell/android-studio/reicast/src/main/res/layout-v14/configure_fragment.xml @@ -636,6 +636,35 @@ + + + + + + + + + + diff --git a/shell/android-studio/reicast/src/main/res/layout/configure_fragment.xml b/shell/android-studio/reicast/src/main/res/layout/configure_fragment.xml index 715a72899..aa4ec85f1 100644 --- a/shell/android-studio/reicast/src/main/res/layout/configure_fragment.xml +++ b/shell/android-studio/reicast/src/main/res/layout/configure_fragment.xml @@ -636,6 +636,35 @@ + + + + + + + + + + diff --git a/shell/android-studio/reicast/src/main/res/values-pl/strings.xml b/shell/android-studio/reicast/src/main/res/values-pl/strings.xml index 5d5e9bb2a..9007c250f 100644 --- a/shell/android-studio/reicast/src/main/res/values-pl/strings.xml +++ b/shell/android-studio/reicast/src/main/res/values-pl/strings.xml @@ -18,6 +18,7 @@ Opcje Dynarec Niestabilne optymalizacje Region DC + Renderuj do tekstury Limit FPS Użyj Mipmap (fix dla starego SGX540) Tryb Szerokoekranowy diff --git a/shell/android-studio/reicast/src/main/res/values-ru/strings.xml b/shell/android-studio/reicast/src/main/res/values-ru/strings.xml index 65cccc0a7..652383a93 100644 --- a/shell/android-studio/reicast/src/main/res/values-ru/strings.xml +++ b/shell/android-studio/reicast/src/main/res/values-ru/strings.xml @@ -38,6 +38,7 @@ Тип кабеля Регион Dreamcast Система ТВ + Рендеринг текстуры (RTT) Ограничение FPS MIP-карты (откл. для SGX540) Широкоэкранный режим diff --git a/shell/android-studio/reicast/src/main/res/values/donottranslate.xml b/shell/android-studio/reicast/src/main/res/values/donottranslate.xml index 72e64ba77..805954e77 100644 --- a/shell/android-studio/reicast/src/main/res/values/donottranslate.xml +++ b/shell/android-studio/reicast/src/main/res/values/donottranslate.xml @@ -61,6 +61,14 @@ 9 - PAL-E + + Disabled - skip frames + Zeros + Ones + Shadow circle + Full + + J E diff --git a/shell/android-studio/reicast/src/main/res/values/strings.xml b/shell/android-studio/reicast/src/main/res/values/strings.xml index 22620e428..a2eb11513 100644 --- a/shell/android-studio/reicast/src/main/res/values/strings.xml +++ b/shell/android-studio/reicast/src/main/res/values/strings.xml @@ -42,6 +42,7 @@ Cable Type DC Region Broadcast + Render to texture Limit FPS Use Mipmaps (fixes SGX540) Widescreen Mode From 5f19eb7ae811362dd3e38d94fde2e29fa51b5b9c Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 11 Nov 2018 20:51:05 +0100 Subject: [PATCH 03/22] Rtt menu options are now handled by GLES --- core/hw/pvr/ta_ctx.cpp | 2 +- core/rend/gles/gldraw.cpp | 24 ++--- core/rend/gles/gles.cpp | 14 ++- core/rend/gles/gles.h | 1 + core/rend/gles/gltex.cpp | 99 +++++++++++++++---- .../emulator/config/OptionsFragment.java | 2 - .../reicast/src/main/jni/src/Android.cpp | 1 - 7 files changed, 103 insertions(+), 40 deletions(-) diff --git a/core/hw/pvr/ta_ctx.cpp b/core/hw/pvr/ta_ctx.cpp index fdf3fd9eb..1115a1849 100644 --- a/core/hw/pvr/ta_ctx.cpp +++ b/core/hw/pvr/ta_ctx.cpp @@ -147,7 +147,7 @@ bool QueueRender(TA_context* ctx) bool too_fast = (cycle_span / time_span) > (SH4_MAIN_CLOCK * 1.2); if ((rqueue && too_fast && settings.pvr.SynchronousRender) || - (rqueue && ctx->rend.isRTT)) { + (settings.dreamcast.rttOption != 0 && rqueue && ctx->rend.isRTT)) { //wait for a frame if // we have another one queue'd and // sh4 run at > 120% on the last slice diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index f2a37fecd..e47eddc15 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -146,18 +146,18 @@ s32 SetTileClip(u32 val, bool set) return 0; if (set && clip_mode) { - if (!pvrrc.isRTT) { - float t = cey; - cey = 480 - csy; - csy = 480 - t; - float dc2s_scale_h = screen_height / 480.0f; - float ds2s_offs_x = (screen_width - dc2s_scale_h * 640) / 2; - csx = csx * dc2s_scale_h + ds2s_offs_x; - cex = cex * dc2s_scale_h + ds2s_offs_x; - csy = csy * dc2s_scale_h; - cey = cey * dc2s_scale_h; - } - glUniform4f(CurrentShader->pp_ClipTest, csx, csy, cex, cey); + if (!pvrrc.isRTT) { + float t = cey; + cey = 480 - csy; + csy = 480 - t; + float dc2s_scale_h = screen_height / 480.0f; + float ds2s_offs_x = (screen_width - dc2s_scale_h * 640) / 2; + csx = csx * dc2s_scale_h + ds2s_offs_x; + cex = cex * dc2s_scale_h + ds2s_offs_x; + csy = csy * dc2s_scale_h; + cey = cey * dc2s_scale_h; + } + glUniform4f(CurrentShader->pp_ClipTest, csx, csy, cex, cey); } return clip_mode; diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index f978e698a..33476d023 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -997,6 +997,8 @@ bool gles_init() if (!gl_create_resources()) return false; + InitShadowCircle(); + #if defined(GLES) && HOST_OS != OS_DARWIN && !defined(TARGET_NACL32) #ifdef TARGET_PANDORA fbdev=open("/dev/fb0", O_RDONLY); @@ -1448,6 +1450,11 @@ void OSD_DRAW() bool ProcessFrame(TA_context* ctx) { + if (ctx->rend.isRTT && settings.dreamcast.rttOption == 0) + { + return false; + } + ctx->rend_inuse.Lock(); ctx->MarkRend(); @@ -1780,8 +1787,6 @@ bool RenderFrame() #endif } - printf("RTT option: %d", settings.dreamcast.rttOption); - //Clear depth //Color is cleared by the bgp if (settings.rend.WideScreen) @@ -1839,7 +1844,10 @@ bool RenderFrame() //restore scale_x scale_x /= scissoring_scale_x; - DrawStrips(); + if (!(is_rtt && (settings.dreamcast.rttOption > 0 && settings.dreamcast.rttOption <= 3))) + { + DrawStrips(); + } #if HOST_OS==OS_WINDOWS //Sleep(40); //to test MT stability diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index 63b841d6a..02e28d072 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -122,6 +122,7 @@ 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); +void InitShadowCircle(); bool CompilePipelineShader(PipelineShader* s); #define TEXTURE_LOAD_ERROR 0 diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 6399ce1aa..c540a755c 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -1,6 +1,7 @@ #include "gles.h" #include "rend/TexCache.h" #include "hw/pvr/pvr_mem.h" +#include /* Textures @@ -20,6 +21,9 @@ Compression look into it, but afaik PVRC is not realtime doable */ +const u32 shadowCircleW = 128; +const u32 shadowCircleH = 128; +u16 shadowCircleTexture[shadowCircleW][shadowCircleH] = {0}; u16 buf[1024*1024]; #if FEAT_HAS_SOFTREND @@ -445,26 +449,16 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) glViewport(0, 0, fbw, fbh); } -void ReadRTT() { - FBT& rv=fb_rtt; - - //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); - - switch(FB_W_CTRL.fb_packmode) - { +void handlePackModeRTT(GLint w, GLint h) +{ + switch (FB_W_CTRL.fb_packmode) { //currently RGB 565 is supported only case 1: //0x1 565 RGB 16 bit { - u16 *dataPointer = temp_tex_buffer; + u16 *dataPointer = temp_tex_buffer; glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, temp_tex_buffer); - for (u32 i = 0; i < w * h; i++) { + for (u32 i = 0; i < w * h; i++) + { buf[i] = ((*dataPointer & 0xF000) >> 12) | ((*dataPointer & 0x0FFF) << 4); *dataPointer++; } @@ -481,7 +475,46 @@ void ReadRTT() { } } -void FreeRTTBuffers() { +void ReadRTT() +{ + FBT& rv=fb_rtt; + + //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) + { + 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; + + 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; + + 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); + } +} + +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; } @@ -568,12 +601,12 @@ text_info raw_GetTexture(TSP tsp, TCW tcw) //return gl texture rv.height = tf->h; - rv.width = tf->w; - rv.pdata = tf->pData; - rv.textype = tf->tex_type; + rv.width = tf->w; + rv.pdata = tf->pData; + rv.textype = tf->tex_type; - return rv; + return rv; } void CollectCleanup() { @@ -602,6 +635,30 @@ void CollectCleanup() { void DoCleanup() { } + +void InitShadowCircle() { + s32 middle_x = shadowCircleW / 2; + s32 middle_y = shadowCircleH / 2; + u32 radius = 15; + + s32 x = 0, y = 0; + for (s32 i = 0; i <= 360; i = i + 2) { + x = s32(radius * cos(i * M_PI / 180)); + y = s32(radius * sin(i * M_PI / 180)); + shadowCircleTexture[middle_x + x][middle_y + y] = 0x5555; + + if (y < 0) { + for (s32 j = 0; j < abs(y); ++j) { + shadowCircleTexture[middle_x + x][middle_y - j] = 0xAAAA; + } + } else { + for (s32 j = 1; j < y; ++j) { + shadowCircleTexture[middle_x + x][middle_y + j] = 0xAAAA; + } + } + } +} + void killtex() { for (TexCacheIter i=TexCache.begin();i!=TexCache.end();i++) diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java index 07e2d1c84..e5f8834c8 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java @@ -378,7 +378,6 @@ public class OptionsFragment extends Fragment { } }); - //---------------------------------------- String[] rtts = getResources().getStringArray(R.array.rtt); Spinner rtt_spnr = (Spinner) getView().findViewById(R.id.rtt_spinner); ArrayAdapter rttAdapter = new ArrayAdapter<>( @@ -394,7 +393,6 @@ public class OptionsFragment extends Fragment { public void onNothingSelected(AdapterView arg0) { } }); -//---------------------------------------- OnCheckedChangeListener limitfps_option = new OnCheckedChangeListener() { diff --git a/shell/android-studio/reicast/src/main/jni/src/Android.cpp b/shell/android-studio/reicast/src/main/jni/src/Android.cpp index deccebceb..844bc732d 100644 --- a/shell/android-studio/reicast/src/main/jni/src/Android.cpp +++ b/shell/android-studio/reicast/src/main/jni/src/Android.cpp @@ -108,7 +108,6 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rtt(JNIEnv *env,jobje settings.dreamcast.rttOption = rtt; } - JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_limitfps(JNIEnv *env,jobject obj, jint limiter) { settings.aica.LimitFPS = limiter; From 4d39c10c9151e1b75697240c98aad03fcd01314a Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 11 Nov 2018 23:14:50 +0100 Subject: [PATCH 04/22] Build fixes --- core/rend/gles/gltex.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index c540a755c..880c1d97a 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -3,6 +3,10 @@ #include "hw/pvr/pvr_mem.h" #include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + /* Textures @@ -427,8 +431,8 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) 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_BORDER_OES); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER_OES); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Create the object that will allow us to render to the aforementioned texture if (!rv.fbo) From e981dd14f822d097881e7612aac62833f1b25475 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 16 Dec 2018 09:35:26 +0100 Subject: [PATCH 05/22] Render to texture full multipass support added; RTT stride textures support added --- core/rend/gles/gles.cpp | 82 ++-- core/rend/gles/gles.h | 13 +- core/rend/gles/gltex.cpp | 409 ++++++++++++------ .../java/com/reicast/emulator/Emulator.java | 2 +- .../emulator/config/OptionsFragment.java | 2 +- 5 files changed, 326 insertions(+), 182 deletions(-) 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 Date: Sat, 22 Dec 2018 19:59:58 +0100 Subject: [PATCH 06/22] RTT: glReadPixels() functions are now compatible with OpenGL ES 2.0 --- core/rend/gles/gltex.cpp | 221 +++++++++++++++++++++++++++++++-------- 1 file changed, 179 insertions(+), 42 deletions(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 6a7f3952c..fc458cc71 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -37,6 +37,7 @@ set delayedUpdateQueue; #endif u16 temp_tex_buffer[1024*1024]; +u32 temp_tex_buffer_32[1024*1024]; extern u32 decoded_colors[3][65536]; typedef void TexConvFP(PixelBuffer* pb,u8* p_in,u32 Width,u32 Height); @@ -440,8 +441,7 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) if (iter != renderedTextures.end()) { renderedTexture = &iter->second; - } - else { + } else { renderedTexture = &renderedTextures[location]; } @@ -466,6 +466,7 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) // Generate and bind a render buffer which will become a depth buffer if (!renderedTexture->depthb) { glGenRenderbuffers(1, &renderedTexture->depthb); + glBindRenderbuffer(GL_RENDERBUFFER, renderedTexture->depthb); /* @@ -491,9 +492,10 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) createTexture(fbw, fbh, channels, fmt, renderedTexture->renderTex); } - // Create the object that will allow us to render to the aforementioned texture + // Create the object that will allow us to render to the aforementioned texture (one for every rtt texture address) if (!renderedTexture->fbo) { glGenFramebuffers(1, &renderedTexture->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, renderedTexture->fbo); // Attach the texture to the FBO @@ -514,54 +516,188 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) glViewport(0, 0, fbw, fbh); } -void handlePackModeRTT(GLint w, GLint h, FBT& fbt) +GLint checkSupportedReadFormat() { - u16 *dataPointer = fbt.texData; + //framebuffer from which we are reading must be bound before + GLint format; + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format); + return format; +} + +GLint checkSupportedReadType() +{ + //framebuffer from which we are reading must be bound before + GLint type; + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type); + return type; +} + +void handleKRGB1555(GLint w, GLint h, FBT &fbt) { const u32 kval_upper_bit = fbt.kval_bit; + + if (checkSupportedReadType() == GL_UNSIGNED_SHORT_5_5_5_1) { + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, fbt.texData); + + // convert RGBA5551 to KRGB1555 + const u16 *dataPointer = fbt.texData; + for (u32 i = 0; i < w * h; i++) { + fbt.texData[i] = (kval_upper_bit << 15) | ((*dataPointer & 0xFFFE) >> 1); + *dataPointer++; + } + } + else { + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + + // convert R8G8B8A8 to KRGB1555 + const u32 *dataPointer32 = temp_tex_buffer_32; + for (u32 i = 0; i < w * h; i++) { + //additional variables just for better visibility + const u8 blue = ((*dataPointer32 & 0x00FF0000UL) >> 19); //5bits for blue + const u8 green = ((*dataPointer32 & 0x0000FF00UL) >> 11); //5bits for green + const u8 red = (*dataPointer32 & 0x000000FFUL) >> 3; //5bits for red + + //convert to 16bit color with K value bit + temp_tex_buffer_32[i] = (kval_upper_bit << 15) | (red << 10) | (green << 5) | blue; + *dataPointer32++; + + //assign to 16bit buffer (type conversions should use static_cast<> in C++) + fbt.texData[i] = (u16)temp_tex_buffer_32[i]; + } + } +} + +void handleRGB565(GLint w, GLint h, FBT &fbt) +{ + if (checkSupportedReadType() == GL_UNSIGNED_SHORT_5_6_5) { + // can be directly read + glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fbt.texData); + } + else { + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + + // convert R8G8B8A8 to RGB565 + const u32 *dataPointer32 = temp_tex_buffer_32; + for (u32 i = 0; i < w * h; i++) { + //additional variables just for better visibility + const u8 blue = ((*dataPointer32 & 0x00FF0000UL) >> 19); //5bits for blue + const u8 green = ((*dataPointer32 & 0x0000FF00UL) >> 10); //6bits for green + const u8 red = (*dataPointer32 & 0x000000FFUL) >> 3; //5bits for red + + //convert to 16bit color + temp_tex_buffer_32[i] = (red << 11) | (green << 5) | blue; + *dataPointer32++; + + //assign to 16bit buffer (type conversions should use static_cast<> in C++) + fbt.texData[i] = (u16)temp_tex_buffer_32[i]; + } + } +} + +void handleARGB4444(GLint w, GLint h, FBT &fbt) +{ + if (checkSupportedReadType() == GL_UNSIGNED_SHORT_4_4_4_4) { + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, fbt.texData); + + // convert RGBA4444 to ARGB4444 + const u16 *dataPointer = fbt.texData; + for (u32 i = 0; i < w * h; i++) { + fbt.texData[i] = ((*dataPointer & 0x000F) << 12) | ((*dataPointer & 0xFFF0) >> 4); + *dataPointer++; + } + } + else { + // convert R8G8B8A8 to ARGB4444 + const u32 *dataPointer32 = temp_tex_buffer_32; + for (u32 i = 0; i < w * h; i++) { + //additional variables just for better visibility + const u8 alpha = ((*dataPointer32 & 0xFF000000UL) >> 28); //4bits for alpha + const u8 blue = ((*dataPointer32 & 0x00FF0000UL) >> 20); //4bits for blue + const u8 green = ((*dataPointer32 & 0x0000FF00UL) >> 12); //4bits for green + const u8 red = (*dataPointer32 & 0x000000FFUL) >> 4; //4bits for red + + //convert to 16bit color with alpha swap + temp_tex_buffer_32[i] = (alpha << 12) | (red << 8) | (green << 4) | blue; + *dataPointer32++; + + //assign to 16bit buffer (type conversions should use static_cast<> in C++) + fbt.texData[i] = (u16)temp_tex_buffer_32[i]; + } + } +} + +void handleARGB1555(GLint w, GLint h, FBT &fbt) { const u32 fb_alpha_threshold = fbt.fb_alpha_threshold; + if (checkSupportedReadType() == GL_UNSIGNED_SHORT_5_5_5_1) { + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, fbt.texData); + + // convert RGBA5551 to ARGB1555 + const u16 *dataPointer = fbt.texData; + 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++; + } + } + else { + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + + // convert R8G8B8A8 to ARGB1555 + const u32 *dataPointer32 = temp_tex_buffer_32; + for (u32 i = 0; i < w * h; i++) { + //additional variables just for better visibility + const u8 alpha = ((*dataPointer32 & 0xFF000000UL) >> 31); //1bit for alpha + const u8 blue = ((*dataPointer32 & 0x00FF0000UL) >> 19); //5bits for blue + const u8 green = ((*dataPointer32 & 0x0000FF00UL) >> 11); //5bits for green + const u8 red = (*dataPointer32 & 0x000000FFUL) >> 3; //5bits for red + + const u8 alphaThresholded = (alpha >= fb_alpha_threshold) ? 1 : 0; + + //convert to 16bit color and make the alpha channel swap + temp_tex_buffer_32[i] = (alphaThresholded << 15) | (red << 10) | (green << 5) | blue; + *dataPointer32++; + + //assign to 16bit buffer (type conversions should use static_cast<> in C++) + fbt.texData[i] = (u16)temp_tex_buffer_32[i]; + } + } +} + +void handlePackModeRTT(GLint w, GLint h, FBT &fbt) +{ 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++) - { - fbt.texData[i] = (kval_upper_bit << 15) | ((*dataPointer & 0xFFFE) >> 1); - *dataPointer++; - } + { + handleKRGB1555(w, h, fbt); break; + } case 1: //0x1 565 RGB 16 bit - glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fbt.texData); + { + handleRGB565(w, h, fbt); 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++; - } + { + handleARGB4444(w, h, fbt); 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++; - } + { + handleARGB1555(w, h, fbt); break; + } default: + { //clear unsupported texture to avoid artifacts 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; + } } } @@ -571,45 +707,46 @@ void ReadRTT() for ( it = renderedTextures.begin(); it != renderedTextures.end(); it++ ) { - if(!it->second.updated) { + FBT &fbt = it->second; + if(!fbt.updated) { continue; } - GLint w = it->second.w; - GLint h = it->second.h; + GLint w = fbt.w; + GLint h = fbt.h; if (settings.dreamcast.rttOption == ShadowCircle) { - glBindTexture(GL_TEXTURE_2D, it->second.tex); + glBindTexture(GL_TEXTURE_2D, fbt.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; + fbt.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); + glBindTexture(GL_TEXTURE_2D, fbt.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; + fbt.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); + glBindTexture(GL_TEXTURE_2D, fbt.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; + fbt.updated = false; } else if (settings.dreamcast.rttOption == Full) { - glBindFramebuffer(GL_FRAMEBUFFER, it->second.fbo); - if (!it->second.texDataValid) { - handlePackModeRTT(w, h, it->second); + glBindFramebuffer(GL_FRAMEBUFFER, fbt.fbo); + if (!fbt.texDataValid) { + handlePackModeRTT(w, h, fbt); } - it->second.texDataValid = true; + fbt.texDataValid = true; } } } From 2a7f4613f313dd5857859cf4b173ab87ede33e8b Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sat, 22 Dec 2018 20:50:42 +0100 Subject: [PATCH 07/22] RTT: Synchronous rendering notice dialog added --- .../src/main/java/com/reicast/emulator/MainActivity.java | 7 +++++++ .../java/com/reicast/emulator/config/OptionsFragment.java | 4 ++++ .../reicast/src/main/res/values-pl/strings.xml | 2 ++ .../android-studio/reicast/src/main/res/values/strings.xml | 5 ++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/MainActivity.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/MainActivity.java index 28376831d..b82e2c149 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/MainActivity.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/MainActivity.java @@ -339,6 +339,13 @@ public class MainActivity extends AppCompatActivity implements builder.show(); } + public void synchronousRenderingNotice() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.synchronous_rendering_notice); + builder.create(); + builder.show(); + } + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java index 56db8b394..89049b26b 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/config/OptionsFragment.java @@ -72,6 +72,7 @@ public class OptionsFragment extends Fragment { void recreateActivity(); void onMainBrowseSelected(String path_entry, boolean games, String query); void launchBIOSdetection(); + void synchronousRenderingNotice(); } @Override @SuppressWarnings("deprecation") @@ -388,6 +389,9 @@ public class OptionsFragment extends Fragment { rtt_spnr.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView parent, View view, int pos, long id) { mPrefs.edit().putInt(Emulator.pref_rtt, pos).apply(); + if (pos == 4) { + mCallback.synchronousRenderingNotice(); + } } public void onNothingSelected(AdapterView arg0) { diff --git a/shell/android-studio/reicast/src/main/res/values-pl/strings.xml b/shell/android-studio/reicast/src/main/res/values-pl/strings.xml index 9007c250f..194d27db1 100644 --- a/shell/android-studio/reicast/src/main/res/values-pl/strings.xml +++ b/shell/android-studio/reicast/src/main/res/values-pl/strings.xml @@ -65,4 +65,6 @@ O nas Oceń nas + Zalecane jest także włączenie opcji `Synchronous Rendering` + diff --git a/shell/android-studio/reicast/src/main/res/values/strings.xml b/shell/android-studio/reicast/src/main/res/values/strings.xml index a2eb11513..d23cd1923 100644 --- a/shell/android-studio/reicast/src/main/res/values/strings.xml +++ b/shell/android-studio/reicast/src/main/res/values/strings.xml @@ -182,4 +182,7 @@ Emu Sound Turbo disk_loading - \ No newline at end of file + + It is recommended to enable `Synchronous Rendering` option as well + + From 127072ec8dbd4c520f8c656de97f3549dfd986a8 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sat, 22 Dec 2018 23:48:04 +0100 Subject: [PATCH 08/22] RTT: Fixed slow rendering of RGBA5551 framebuffer format on Adreno 506 --- core/rend/gles/gles.cpp | 32 ++++++++++++++++++++++++-------- core/rend/gles/gltex.cpp | 20 ++++++++++++++++++-- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index b61e709e2..5330218d8 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -1733,27 +1733,43 @@ bool RenderFrame() //setup render target first if (is_rtt) { - GLuint channels,format; + const char * renderer = (char *)glGetString(GL_RENDERER); + const char * adreno506Renderer = "Adreno (TM) 506"; + GLuint channels, format; switch(FB_W_CTRL.fb_packmode) { case 0: //0x0 0555 KRGB 16 bit (default) Bit 15 is the value of fb_kval[7]. channels=GL_RGBA; - format=GL_UNSIGNED_SHORT_5_5_5_1; + // When using RGBA5551 format on Adreno 506, rendering is extremely slow + // (probably by some internal format conversions), thus using GL_UNSIGNED_BYTE + if (!strcmp(renderer, adreno506Renderer)) { + format = GL_UNSIGNED_BYTE; + } + else { + format = GL_UNSIGNED_SHORT_5_5_5_1; + } break; case 1: //0x1 565 RGB 16 bit - channels=GL_RGB; - format=GL_UNSIGNED_SHORT_5_6_5; + channels = GL_RGB; + format = GL_UNSIGNED_SHORT_5_6_5; break; case 2: //0x2 4444 ARGB 16 bit - channels=GL_RGBA; - format=GL_UNSIGNED_SHORT_4_4_4_4; + channels = GL_RGBA; + 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. - channels=GL_RGBA; - format=GL_UNSIGNED_SHORT_5_5_5_1; + channels = GL_RGBA; + // When using RGBA5551 format on Adreno 506, rendering is extremely slow + // (probably by some internal format conversions), thus using GL_UNSIGNED_BYTE + if (!strcmp(renderer, adreno506Renderer)) { + format = GL_UNSIGNED_BYTE; + } + else { + format = GL_UNSIGNED_SHORT_5_5_5_1; + } break; case 4: //0x4 888 RGB 24 bit packed diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index fc458cc71..743fbfdac 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -534,8 +534,9 @@ GLint checkSupportedReadType() void handleKRGB1555(GLint w, GLint h, FBT &fbt) { const u32 kval_upper_bit = fbt.kval_bit; + GLint framebufferReadType = checkSupportedReadType(); - if (checkSupportedReadType() == GL_UNSIGNED_SHORT_5_5_5_1) { + if (framebufferReadType == GL_UNSIGNED_SHORT_5_5_5_1) { glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, fbt.texData); // convert RGBA5551 to KRGB1555 @@ -545,6 +546,13 @@ void handleKRGB1555(GLint w, GLint h, FBT &fbt) { *dataPointer++; } } + else if (framebufferReadType == GL_UNSIGNED_BYTE) { + // Adreno 506 slow rendering fix - 'texconv' in case of RGBA5551 format is not needed + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + glBindTexture(GL_TEXTURE_2D, fbt.tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + fbt.updated = false; + } else { glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); @@ -627,8 +635,9 @@ void handleARGB4444(GLint w, GLint h, FBT &fbt) void handleARGB1555(GLint w, GLint h, FBT &fbt) { const u32 fb_alpha_threshold = fbt.fb_alpha_threshold; + GLint framebufferReadType = checkSupportedReadType(); - if (checkSupportedReadType() == GL_UNSIGNED_SHORT_5_5_5_1) { + if (framebufferReadType == GL_UNSIGNED_SHORT_5_5_5_1) { glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, fbt.texData); // convert RGBA5551 to ARGB1555 @@ -640,6 +649,13 @@ void handleARGB1555(GLint w, GLint h, FBT &fbt) { *dataPointer++; } } + else if (framebufferReadType == GL_UNSIGNED_BYTE) { + // Adreno 506 slow rendering fix - 'texconv' in case of RGBA5551 format is not needed + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + glBindTexture(GL_TEXTURE_2D, fbt.tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + fbt.updated = false; + } else { glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); From 7450c247d3fc195af77199c35350024f3d1dff88 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 23 Dec 2018 00:11:10 +0100 Subject: [PATCH 09/22] Minor formatting fixes --- core/rend/gles/gles.cpp | 2 +- core/rend/gles/gles.h | 2 +- core/rend/gles/gltex.cpp | 17 ++++++++--------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 5330218d8..8fba05bf4 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -1859,7 +1859,7 @@ bool RenderFrame() if (!(is_rtt && (settings.dreamcast.rttOption > Disabled && settings.dreamcast.rttOption <= ShadowCircle))) { - checkIfUpdated(); + rttCheckIfUpdated(); DrawStrips(); } diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index fae84a68f..86b665490 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -57,7 +57,7 @@ enum rttSelectedOption }; void DrawStrips(); -void checkIfUpdated(); +void rttCheckIfUpdated(); struct PipelineShader { diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 743fbfdac..a2b9915e8 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -296,15 +296,13 @@ struct TextureCacheData //texture conversion work PixelBuffer pbt; - pbt.p_buffer_start=pbt.p_current_line=temp_tex_buffer; - - - u32 stride=w; + pbt.p_buffer_start = pbt.p_current_line = temp_tex_buffer; + u32 stride = w; if (tcw.StrideSel && tcw.ScanOrder && tex->PL) - stride=(TEXT_CONTROL&31)*32; //I think this needs +1 ? + stride = (TEXT_CONTROL & 31) * 32; - if(texconv!=0) + if(texconv != 0) { if (isSourceVram) { pbt.pixels_per_line = w; @@ -332,11 +330,12 @@ struct TextureCacheData if (texID) { glBindTexture(GL_TEXTURE_2D, texID); - GLuint comps=textype == GL_UNSIGNED_SHORT_5_6_5 ? GL_RGB : GL_RGBA; + 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 { + } + else { glTexImage2D(GL_TEXTURE_2D, 0, comps, stride, h, 0, comps, textype, temp_tex_buffer); } if (tcw.MipMapped && settings.rend.UseMipmaps) @@ -767,7 +766,7 @@ void ReadRTT() } } -void checkIfUpdated() { +void rttCheckIfUpdated() { if(!pvrrc.isRTT && delayedUpdateQueue.size()) { for (set::iterator it=delayedUpdateQueue.begin(); it != delayedUpdateQueue.end(); ++it) { From 2aadb3cdd446fff8e304e995928c9cbf55391234 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Mon, 7 Jan 2019 21:02:04 +0100 Subject: [PATCH 10/22] RTT: Stencil support added (extension required) --- core/rend/gles/gltex.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index a2b9915e8..be96f016f 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -403,7 +403,7 @@ struct FBT { u32 texAddress; u16 texData[1024*1024]; - GLuint depthb; + GLuint renderBuffer; GLuint tex; GLuint renderTex; GLuint fbo; @@ -463,10 +463,10 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) } // Generate and bind a render buffer which will become a depth buffer - if (!renderedTexture->depthb) { - glGenRenderbuffers(1, &renderedTexture->depthb); + if (!renderedTexture->renderBuffer) { + glGenRenderbuffers(1, &renderedTexture->renderBuffer); - glBindRenderbuffer(GL_RENDERBUFFER, renderedTexture->depthb); + glBindRenderbuffer(GL_RENDERBUFFER, renderedTexture->renderBuffer); /* Currently it is unknown to GL that we want our new render buffer to be a depth buffer. @@ -475,7 +475,10 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) */ #ifdef GLES - if (isExtensionSupported("GL_OES_depth24")) { + if (isExtensionSupported("GL_OES_packed_depth_stencil")) { + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, fbw, fbh); + } + else if (isExtensionSupported("GL_OES_depth24")) { glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, fbw, fbh); } else { @@ -500,8 +503,11 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) // 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, renderedTexture->depthb); + // Attach the depth (and/or stencil) buffer we created earlier to our FBO. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); + if (isExtensionSupported("GL_OES_packed_depth_stencil")) { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); + } // Check that our FBO creation was successful GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); From 27360a1c41a05c143ee0ef067beb2ddbb3bbc8f3 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sat, 12 Jan 2019 12:16:33 +0100 Subject: [PATCH 11/22] Lgtm warnings fixed --- core/rend/gles/gltex.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index be96f016f..6049274c5 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -420,14 +420,14 @@ struct FBT FBT(): initialized(false), updated(false), tf({0}), tex(0), renderTex(0), texDataValid(false) {} }; -void createTexture(u32 w, u32 h, u32 format, u32 type, GLuint & textureID) { +void createTexture(u32 w, u32 h, u32 textureFormat, u32 textureType, 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); + glTexImage2D(GL_TEXTURE_2D, 0, textureFormat, w, h, 0, textureFormat, textureType, 0); } map renderedTextures; @@ -524,17 +524,17 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) GLint checkSupportedReadFormat() { //framebuffer from which we are reading must be bound before - GLint format; - glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format); - return format; + GLint readFormat; + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); + return readFormat; } GLint checkSupportedReadType() { //framebuffer from which we are reading must be bound before - GLint type; - glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type); - return type; + GLint readType; + glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); + return readType; } void handleKRGB1555(GLint w, GLint h, FBT &fbt) { @@ -715,7 +715,7 @@ void handlePackModeRTT(GLint w, GLint h, FBT &fbt) default: { //clear unsupported texture to avoid artifacts - memset(temp_tex_buffer, '\0', w * h); + memset(temp_tex_buffer, '\0', (size_t)((long long) 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; } From a9affb8ac23fda890677b7b798f0cfe381c7ddb5 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 13 Jan 2019 19:04:33 +0100 Subject: [PATCH 12/22] RTT: Stencil support for full OpenGL >= 3.0 added --- core/rend/gles/gltex.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 6049274c5..4034157c5 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -485,7 +485,8 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, fbw, fbh); } #else - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbw, fbh); + //OpenGL >= 3.0 is required + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fbw, fbh); #endif } @@ -505,10 +506,14 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) // Attach the depth (and/or stencil) buffer we created earlier to our FBO. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); +#ifdef GLES if (isExtensionSupported("GL_OES_packed_depth_stencil")) { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); } - +#else + //OpenGL >= 3.0 is required + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); +#endif // Check that our FBO creation was successful GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); From 6499a825138e93350b71471b5538ab502e43bfc6 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 13 Jan 2019 22:15:00 +0100 Subject: [PATCH 13/22] RTT: Additional small fixes --- core/rend/gles/gltex.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 4034157c5..d8037356b 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -543,7 +543,7 @@ GLint checkSupportedReadType() } void handleKRGB1555(GLint w, GLint h, FBT &fbt) { - const u32 kval_upper_bit = fbt.kval_bit; + const u32 kval_bit = fbt.kval_bit; GLint framebufferReadType = checkSupportedReadType(); if (framebufferReadType == GL_UNSIGNED_SHORT_5_5_5_1) { @@ -552,13 +552,16 @@ void handleKRGB1555(GLint w, GLint h, FBT &fbt) { // convert RGBA5551 to KRGB1555 const u16 *dataPointer = fbt.texData; for (u32 i = 0; i < w * h; i++) { - fbt.texData[i] = (kval_upper_bit << 15) | ((*dataPointer & 0xFFFE) >> 1); + fbt.texData[i] = (kval_bit << 15) | ((*dataPointer & 0xFFFE) >> 1); *dataPointer++; } } else if (framebufferReadType == GL_UNSIGNED_BYTE) { // Adreno 506 slow rendering fix - 'texconv' in case of RGBA5551 format is not needed glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + for (u32 i = 0; i < w * h; i++) { + temp_tex_buffer_32[i] = (kval_bit << 31) | (temp_tex_buffer_32[i] & 0x00FFFFFF); + } glBindTexture(GL_TEXTURE_2D, fbt.tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); fbt.updated = false; @@ -575,7 +578,7 @@ void handleKRGB1555(GLint w, GLint h, FBT &fbt) { const u8 red = (*dataPointer32 & 0x000000FFUL) >> 3; //5bits for red //convert to 16bit color with K value bit - temp_tex_buffer_32[i] = (kval_upper_bit << 15) | (red << 10) | (green << 5) | blue; + temp_tex_buffer_32[i] = (kval_bit << 15) | (red << 10) | (green << 5) | blue; *dataPointer32++; //assign to 16bit buffer (type conversions should use static_cast<> in C++) @@ -624,6 +627,8 @@ void handleARGB4444(GLint w, GLint h, FBT &fbt) } } else { + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + // convert R8G8B8A8 to ARGB4444 const u32 *dataPointer32 = temp_tex_buffer_32; for (u32 i = 0; i < w * h; i++) { @@ -662,6 +667,10 @@ void handleARGB1555(GLint w, GLint h, FBT &fbt) { else if (framebufferReadType == GL_UNSIGNED_BYTE) { // Adreno 506 slow rendering fix - 'texconv' in case of RGBA5551 format is not needed glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + for (u32 i = 0; i < w * h; i++) { + const u8 alphaThresholded = ((temp_tex_buffer_32[i] >> 31) >= fb_alpha_threshold) ? 1 : 0; + temp_tex_buffer_32[i] = (alphaThresholded << 31) | (temp_tex_buffer_32[i] & 0x00FFFFFF); + } glBindTexture(GL_TEXTURE_2D, fbt.tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); fbt.updated = false; From 77d997401b994225a75c600a2036d1adf5cb0574 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Mon, 14 Jan 2019 19:09:05 +0100 Subject: [PATCH 14/22] RTT: Performance improved for DC RGB565 and ARGB4444 textures - glReadPixels() removed --- core/rend/gles/gltex.cpp | 136 +++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 69 deletions(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index d8037356b..1f32be7e7 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -413,6 +413,7 @@ struct FBT u32 kval_bit; u32 fb_alpha_threshold; u32 fb_packmode; + bool is565; bool texDataValid; bool updated; bool initialized; @@ -420,7 +421,8 @@ struct FBT FBT(): initialized(false), updated(false), tf({0}), tex(0), renderTex(0), texDataValid(false) {} }; -void createTexture(u32 w, u32 h, u32 textureFormat, u32 textureType, GLuint & textureID) { +void createTexture(u32 w, u32 h, u32 textureFormat, u32 textureType, GLuint & textureID) +{ glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -452,8 +454,9 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) renderedTexture->fb_alpha_threshold = FB_W_CTRL.fb_alpha_threshold; renderedTexture->w = fbw; renderedTexture->h = fbh; + renderedTexture->is565 = (fmt == GL_UNSIGNED_SHORT_5_6_5); - if (!renderedTexture->tex) { + if (!renderedTexture->tex && (fmt != GL_UNSIGNED_SHORT_5_6_5) && (fmt != GL_UNSIGNED_SHORT_4_4_4_4)) { createTexture(fbw, fbh, channels, fmt, renderedTexture->tex); } @@ -587,67 +590,6 @@ void handleKRGB1555(GLint w, GLint h, FBT &fbt) { } } -void handleRGB565(GLint w, GLint h, FBT &fbt) -{ - if (checkSupportedReadType() == GL_UNSIGNED_SHORT_5_6_5) { - // can be directly read - glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fbt.texData); - } - else { - glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); - - // convert R8G8B8A8 to RGB565 - const u32 *dataPointer32 = temp_tex_buffer_32; - for (u32 i = 0; i < w * h; i++) { - //additional variables just for better visibility - const u8 blue = ((*dataPointer32 & 0x00FF0000UL) >> 19); //5bits for blue - const u8 green = ((*dataPointer32 & 0x0000FF00UL) >> 10); //6bits for green - const u8 red = (*dataPointer32 & 0x000000FFUL) >> 3; //5bits for red - - //convert to 16bit color - temp_tex_buffer_32[i] = (red << 11) | (green << 5) | blue; - *dataPointer32++; - - //assign to 16bit buffer (type conversions should use static_cast<> in C++) - fbt.texData[i] = (u16)temp_tex_buffer_32[i]; - } - } -} - -void handleARGB4444(GLint w, GLint h, FBT &fbt) -{ - if (checkSupportedReadType() == GL_UNSIGNED_SHORT_4_4_4_4) { - glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, fbt.texData); - - // convert RGBA4444 to ARGB4444 - const u16 *dataPointer = fbt.texData; - for (u32 i = 0; i < w * h; i++) { - fbt.texData[i] = ((*dataPointer & 0x000F) << 12) | ((*dataPointer & 0xFFF0) >> 4); - *dataPointer++; - } - } - else { - glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); - - // convert R8G8B8A8 to ARGB4444 - const u32 *dataPointer32 = temp_tex_buffer_32; - for (u32 i = 0; i < w * h; i++) { - //additional variables just for better visibility - const u8 alpha = ((*dataPointer32 & 0xFF000000UL) >> 28); //4bits for alpha - const u8 blue = ((*dataPointer32 & 0x00FF0000UL) >> 20); //4bits for blue - const u8 green = ((*dataPointer32 & 0x0000FF00UL) >> 12); //4bits for green - const u8 red = (*dataPointer32 & 0x000000FFUL) >> 4; //4bits for red - - //convert to 16bit color with alpha swap - temp_tex_buffer_32[i] = (alpha << 12) | (red << 8) | (green << 4) | blue; - *dataPointer32++; - - //assign to 16bit buffer (type conversions should use static_cast<> in C++) - fbt.texData[i] = (u16)temp_tex_buffer_32[i]; - } - } -} - void handleARGB1555(GLint w, GLint h, FBT &fbt) { const u32 fb_alpha_threshold = fbt.fb_alpha_threshold; GLint framebufferReadType = checkSupportedReadType(); @@ -710,13 +652,14 @@ void handlePackModeRTT(GLint w, GLint h, FBT &fbt) case 1: //0x1 565 RGB 16 bit { - handleRGB565(w, h, fbt); + //handled elsewhere break; } case 2: //0x2 4444 ARGB 16 bit { - handleARGB4444(w, h, fbt); + fbt.tex = fbt.renderTex; + fbt.updated = false; break; } @@ -777,7 +720,9 @@ void ReadRTT() } else if (settings.dreamcast.rttOption == Full) { - glBindFramebuffer(GL_FRAMEBUFFER, fbt.fbo); + if (fbt.fb_packmode != 1) { + glBindFramebuffer(GL_FRAMEBUFFER, fbt.fbo); + } if (!fbt.texDataValid) { handlePackModeRTT(w, h, fbt); } @@ -791,7 +736,7 @@ void rttCheckIfUpdated() { { 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) + if (renderedTextures[*it].initialized && renderedTextures[*it].updated) { renderedTextures[*it].tf.Update(false, renderedTextures[*it].texData); renderedTextures[*it].updated = false; @@ -815,8 +760,55 @@ void initializeRttTexture(const TSP & tsp, const TCW & tcw, FBT * tempRenderedTe } } -GLuint gl_GetTexture(TSP tsp, TCW tcw) { +void handleRGB565Exceptions(FBT &fbt, u32 newTexAddr) +{ + GLint w = fbt.w; + GLint h = fbt.h; + if (fbt.tf.tex->type != GL_UNSIGNED_SHORT_5_6_5) + { + if (!fbt.tex || (fbt.tex == fbt.renderTex)) { + createTexture((u32) w, (u32) h, GL_RGBA, fbt.tf.tex->type, fbt.tex); + } + fbt.tf.texID = fbt.tex; + + glBindFramebuffer(GL_FRAMEBUFFER, fbt.fbo); + if (checkSupportedReadType() == GL_UNSIGNED_SHORT_5_6_5) { + // can be directly read + glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fbt.texData); + } + else { + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, temp_tex_buffer_32); + + // convert R8G8B8A8 to RGB565 + const u32 *dataPointer32 = temp_tex_buffer_32; + for (u32 i = 0; i < w * h; i++) { + //additional variables just for better visibility + const u8 blue = ((*dataPointer32 & 0x00FF0000UL) >> 19); //5bits for blue + const u8 green = ((*dataPointer32 & 0x0000FF00UL) >> 10); //6bits for green + const u8 red = (*dataPointer32 & 0x000000FFUL) >> 3; //5bits for red + + //convert to 16bit color + temp_tex_buffer_32[i] = (red << 11) | (green << 5) | blue; + *dataPointer32++; + + //assign to 16bit buffer (type conversions should use static_cast<> in C++) + fbt.texData[i] = (u16)temp_tex_buffer_32[i]; + } + } + delayedUpdateQueue.insert(newTexAddr); + } + else { + if (fbt.tex && (fbt.tex != fbt.renderTex)) { //to avoid memory leaks + glDeleteTextures(1, &fbt.tex); + } + fbt.tex = fbt.renderTex; + fbt.updated = false; + } +} + +GLuint gl_GetTexture(TSP tsp, TCW tcw) +{ FBT* tempRenderedTexture = NULL; map::iterator it = renderedTextures.find(tcw.TexAddr); if (it != renderedTextures.end()) { @@ -830,13 +822,19 @@ GLuint gl_GetTexture(TSP tsp, TCW tcw) { //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) + if (tempRenderedTexture->updated && !tempRenderedTexture->is565) { delayedUpdateQueue.insert(tcw.TexAddr); tempRenderedTexture->tf.tsp = tsp; tempRenderedTexture->tf.Create(false); tempRenderedTexture->tf.texID = tempRenderedTexture->tex; } + else if (tempRenderedTexture->updated && tempRenderedTexture->is565) + { + tempRenderedTexture->tf.tsp = tsp; + tempRenderedTexture->tf.Create(false); + handleRGB565Exceptions(*tempRenderedTexture, tcw.TexAddr); + } return tempRenderedTexture->tex; } } From 86339c337d27fbda88f08da03993b3f99a85df2b Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Fri, 18 Jan 2019 19:46:46 +0100 Subject: [PATCH 15/22] RTT: Support for OpenGL 2 added --- core/rend/gles/gltex.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 1f32be7e7..f1a3aa079 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -488,8 +488,12 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, fbw, fbh); } #else - //OpenGL >= 3.0 is required - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fbw, fbh); + if (!strcmp(gl.gl_version, "GL2")) { + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbw, fbh); + } + else { + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fbw, fbh); + } #endif } @@ -514,8 +518,10 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); } #else - //OpenGL >= 3.0 is required - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); + if (!strcmp(gl.gl_version, "GL3")) { + //OpenGL >= 3.0 is required + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); + } #endif // Check that our FBO creation was successful GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); From 88b9debc891aa1bf2019576b6b1e86a4ae3d505f Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 20 Jan 2019 11:03:30 +0100 Subject: [PATCH 16/22] Revert "RTT: Support for OpenGL 2 added" This reverts commit 86339c337d27fbda88f08da03993b3f99a85df2b. --- core/rend/gles/gltex.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index f1a3aa079..1f32be7e7 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -488,12 +488,8 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, fbw, fbh); } #else - if (!strcmp(gl.gl_version, "GL2")) { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, fbw, fbh); - } - else { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fbw, fbh); - } + //OpenGL >= 3.0 is required + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fbw, fbh); #endif } @@ -518,10 +514,8 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); } #else - if (!strcmp(gl.gl_version, "GL3")) { - //OpenGL >= 3.0 is required - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); - } + //OpenGL >= 3.0 is required + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->renderBuffer); #endif // Check that our FBO creation was successful GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); From a65436cc6c0e240f480ae68308e31b2270fb8ef5 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Fri, 8 Feb 2019 22:15:45 +0100 Subject: [PATCH 17/22] Handle dynamic resolution change during emulation (LRR mode) --- core/rend/gles/gles.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 946550598..fc0191b0a 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -483,6 +483,10 @@ gl_ctx gl; int screen_width; int screen_height; + +int currentScreenWidth = -1; +int currentScreenHeight = -1; + GLuint fogTextureId; GLFramebufferData fullscreenQuad; @@ -1634,15 +1638,16 @@ void fullscreenQuadCreateTemporaryFBO(float & screenToNativeXScale, float & scre // Generate and bind a render buffer which will become a depth buffer if (!fullscreenQuad.framebufferRenderbuffer) { glGenRenderbuffers(1, &fullscreenQuad.framebufferRenderbuffer); + } + if (currentScreenWidth != screen_width || currentScreenHeight != screen_height) { + glBindRenderbuffer(GL_RENDERBUFFER, fullscreenQuad.framebufferRenderbuffer); #ifdef GLES if (isExtensionSupported("GL_OES_packed_depth_stencil")) { glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, screen_width, screen_height); - } - else if (isExtensionSupported("GL_OES_depth24")) { + } else if (isExtensionSupported("GL_OES_depth24")) { glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, screen_width, screen_height); - } - else { + } else { glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width, screen_height); } #else @@ -1661,6 +1666,10 @@ void fullscreenQuadCreateTemporaryFBO(float & screenToNativeXScale, float & scre glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); } + if (currentScreenWidth != screen_width || currentScreenHeight != screen_height) { + glBindTexture(GL_TEXTURE_2D, fullscreenQuad.framebufferTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + } // Create the object that will allow us to render to the aforementioned texture (one for every rtt texture address) if (!fullscreenQuad.framebuffer) { @@ -2039,6 +2048,8 @@ bool RenderFrame() } else { fullscreenQuadCreateTemporaryFBO(screenToNativeXScale, screenToNativeYScale); + currentScreenWidth = screen_width; + currentScreenHeight = screen_height; } #endif } @@ -2089,7 +2100,7 @@ bool RenderFrame() printf("SCI: %f, %f, %f, %f\n", offs_x+pvrrc.fb_X_CLIP.min/scale_x,(pvrrc.fb_Y_CLIP.min/scale_y)*dc2s_scale_h,(pvrrc.fb_X_CLIP.max-pvrrc.fb_X_CLIP.min+1)/scale_x*dc2s_scale_h,(pvrrc.fb_Y_CLIP.max-pvrrc.fb_Y_CLIP.min+1)/scale_y*dc2s_scale_h); #endif - if (settings.rend.VerticalResolution == 100 && settings.rend.HorizontalResolution == 100) { + if (is_rtt || (settings.rend.VerticalResolution == 100 && settings.rend.HorizontalResolution == 100)) { if (settings.rend.WideScreen && pvrrc.fb_X_CLIP.min == 0 && ((pvrrc.fb_X_CLIP.max + 1) / scale_x == 640) && (pvrrc.fb_Y_CLIP.min == 0) && ((pvrrc.fb_Y_CLIP.max + 1) / scale_y == 480)) { From 8893f974351d7e5c94f71ded51ab081a9bba4870 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Fri, 8 Feb 2019 21:24:09 +0100 Subject: [PATCH 18/22] Handle odd screen resolution (POCOPHONE fix) --- core/rend/gles/gldraw.cpp | 13 +++++++++++-- core/rend/gles/gles.cpp | 12 +++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index 1251e2722..8305ead56 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -1175,8 +1175,17 @@ void fullscreenQuadPrepareFramebuffer(float xScale, float yScale) { // Reduce width to keep 4:3 aspect ratio (640x480) u32 reducedWidth = 4 * screen_height / 3; - u32 reducedWidthOffset = (screen_width - reducedWidth) / 2; - glScissor(reducedWidthOffset, 0, reducedWidth, screen_height); + + // handle odd/even screen width + if (screen_width % 2 == 0) { + u32 reducedWidthOffset = (screen_width - reducedWidth) / 2; + glScissor(reducedWidthOffset, 0, reducedWidth, screen_height); + } + else { + u32 reducedWidthOffset = (screen_width + 1 - reducedWidth) / 2; + glScissor(reducedWidthOffset, 0, reducedWidth - 1, screen_height); + } + if (settings.rend.WideScreen && (pvrrc.fb_X_CLIP.min==0) && ((pvrrc.fb_X_CLIP.max+1)/xScale==640) && (pvrrc.fb_Y_CLIP.min==0) && ((pvrrc.fb_Y_CLIP.max+1)/yScale==480 )) diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index fc0191b0a..550d53ead 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -1902,6 +1902,10 @@ bool RenderFrame() */ float dc2s_scale_h = screen_height / 480.0; float ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0) / 2; + // handle odd screen width + if (screen_width % 2) { + ds2s_offs_x = (screen_width + 1 - dc2s_scale_h * 640.0) / 2; + } if (!is_rtt) { ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x); @@ -2118,7 +2122,13 @@ bool RenderFrame() width *= dc2s_scale_h; height *= dc2s_scale_h; } - glScissor(min_x + 0.5f, min_y + 0.5f, width + 0.5f, height + 0.5f); + // handle odd/even screen width + if (screen_width % 2 == 0) { + glScissor(min_x + 0.5f, min_y + 0.5f, width + 0.5f, height + 0.5f); + } + else { + glScissor(min_x + 0.5f, min_y + 0.5f, width + 0.5f - 1, height + 0.5f); + } glEnable(GL_SCISSOR_TEST); } } From 7869a84f88881a6fb842afb5b4bcb4afde1f571d Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sat, 9 Feb 2019 23:59:16 +0100 Subject: [PATCH 19/22] Additional fixes/cleanup --- core/rend/gles/gldraw.cpp | 6 ++---- core/rend/gles/gles.cpp | 35 +++++++++-------------------------- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index 8305ead56..6b3d438eb 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -1183,12 +1183,10 @@ void fullscreenQuadPrepareFramebuffer(float xScale, float yScale) { } else { u32 reducedWidthOffset = (screen_width + 1 - reducedWidth) / 2; - glScissor(reducedWidthOffset, 0, reducedWidth - 1, screen_height); + glScissor(reducedWidthOffset, 0, reducedWidth, screen_height); } - if (settings.rend.WideScreen && - (pvrrc.fb_X_CLIP.min==0) && ((pvrrc.fb_X_CLIP.max+1)/xScale==640) && - (pvrrc.fb_Y_CLIP.min==0) && ((pvrrc.fb_Y_CLIP.max+1)/yScale==480 )) + if (settings.rend.WideScreen) { glDisable(GL_SCISSOR_TEST); } diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 550d53ead..0d488fb11 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -2091,9 +2091,6 @@ bool RenderFrame() glBufferData(GL_ARRAY_BUFFER,pvrrc.modtrig.bytes(),pvrrc.modtrig.head(),GL_STREAM_DRAW); glCheck(); } - int offs_x=ds2s_offs_x+0.5f; - //this needs to be scaled - //not all scaling affects pixel operations, scale to adjust for that scale_x *= scissoring_scale_x; @@ -2105,30 +2102,16 @@ bool RenderFrame() #endif if (is_rtt || (settings.rend.VerticalResolution == 100 && settings.rend.HorizontalResolution == 100)) { - if (settings.rend.WideScreen && pvrrc.fb_X_CLIP.min == 0 && - ((pvrrc.fb_X_CLIP.max + 1) / scale_x == 640) && (pvrrc.fb_Y_CLIP.min == 0) && - ((pvrrc.fb_Y_CLIP.max + 1) / scale_y == 480)) { + glScissor(ds2s_offs_x + 0.5f + pvrrc.fb_X_CLIP.min / scale_x, + (pvrrc.fb_Y_CLIP.min / scale_y) * dc2s_scale_h, + (pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1) / scale_x * dc2s_scale_h, + (pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1) / scale_y * dc2s_scale_h); + if (settings.rend.WideScreen) + { glDisable(GL_SCISSOR_TEST); - } else { - float width = (pvrrc.fb_X_CLIP.max - pvrrc.fb_X_CLIP.min + 1) / scale_x; - float height = (pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1) / scale_y; - float min_x = pvrrc.fb_X_CLIP.min / scale_x; - float min_y = pvrrc.fb_Y_CLIP.min / scale_y; - if (!is_rtt) { - // Add x offset for aspect ratio > 4/3 - min_x = min_x * dc2s_scale_h + ds2s_offs_x; - // Invert y coordinates when rendering to screen - min_y = screen_height - (min_y + height) * dc2s_scale_h; - width *= dc2s_scale_h; - height *= dc2s_scale_h; - } - // handle odd/even screen width - if (screen_width % 2 == 0) { - glScissor(min_x + 0.5f, min_y + 0.5f, width + 0.5f, height + 0.5f); - } - else { - glScissor(min_x + 0.5f, min_y + 0.5f, width + 0.5f - 1, height + 0.5f); - } + } + else + { glEnable(GL_SCISSOR_TEST); } } From 8d4188159e2bd264972968850a48427949f6e09b Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Sun, 10 Feb 2019 01:11:09 +0100 Subject: [PATCH 20/22] Vertical scale factor support added - fixes Crazy Taxi pause menu background positioning --- core/rend/gles/gltex.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 1f32be7e7..6820a5fc4 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -432,6 +432,17 @@ void createTexture(u32 w, u32 h, u32 textureFormat, u32 textureType, GLuint & te glTexImage2D(GL_TEXTURE_2D, 0, textureFormat, w, h, 0, textureFormat, textureType, 0); } +double binaryFractionToDouble(u32 numberIntegerPart, u32 numberFractionalPart, u32 fractionalPartLength) +{ + double sum = 0; + + for (u32 i = 1; i <= fractionalPartLength; ++i) { + sum += !!(numberFractionalPart & (1 << fractionalPartLength - i)) * pow(.5, i); + } + + return numberIntegerPart + sum; +} + map renderedTextures; void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) @@ -446,6 +457,12 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) renderedTexture = &renderedTextures[location]; } + u32 fbhViewport = fbh; + if (SCALER_CTL.vscalefactor != 0x0400) { + fbh = round(fbw * binaryFractionToDouble( + SCALER_CTL.vscalefactor >> 10, SCALER_CTL.vscalefactor & 0x3FF, 10)); + } + renderedTexture->texAddress = location; renderedTexture->fb_packmode = FB_W_CTRL.fb_packmode; renderedTexture->updated = true; @@ -526,7 +543,7 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) glBindFramebuffer(GL_FRAMEBUFFER, renderedTexture->fbo); } - glViewport(0, 0, fbw, fbh); + glViewport(0, 0, fbw, fbhViewport); } GLint checkSupportedReadFormat() From 3b951c0232d851bea26ee221dd8cb9d38f6f0105 Mon Sep 17 00:00:00 2001 From: Marcel <5397997+mar753@users.noreply.github.com> Date: Mon, 11 Feb 2019 11:15:01 +0100 Subject: [PATCH 21/22] Vertical scale factor support added - typo fix --- core/rend/gles/gltex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 6820a5fc4..331f8c4f9 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -459,7 +459,7 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) u32 fbhViewport = fbh; if (SCALER_CTL.vscalefactor != 0x0400) { - fbh = round(fbw * binaryFractionToDouble( + fbh = round(fbh * binaryFractionToDouble( SCALER_CTL.vscalefactor >> 10, SCALER_CTL.vscalefactor & 0x3FF, 10)); } From d370fd67099cd49774917e2a25e5d607faf61149 Mon Sep 17 00:00:00 2001 From: Marcel Szewczyk Date: Mon, 11 Feb 2019 19:00:13 +0100 Subject: [PATCH 22/22] PR requested changes; Adreno 506 generalized to Adreno --- core/rend/gles/gles.cpp | 12 ++++++------ core/rend/gles/gles.h | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 0d488fb11..5d07d6a8a 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -563,6 +563,8 @@ bool isExtensionSupported(const char * name) { screen_width=w; screen_height=h; + gl.renderer = (char *)glGetString(GL_RENDERER); + printf("EGL config: %p, %08X, %08X %dx%d\n",gl.setup.context,gl.setup.display,gl.setup.surface,w,h); return true; } @@ -1983,16 +1985,14 @@ bool RenderFrame() //setup render target first if (is_rtt) { - const char * renderer = (char *)glGetString(GL_RENDERER); - const char * adreno506Renderer = "Adreno (TM) 506"; GLuint channels, format; switch(FB_W_CTRL.fb_packmode) { case 0: //0x0 0555 KRGB 16 bit (default) Bit 15 is the value of fb_kval[7]. channels=GL_RGBA; // When using RGBA5551 format on Adreno 506, rendering is extremely slow - // (probably by some internal format conversions), thus using GL_UNSIGNED_BYTE - if (!strcmp(renderer, adreno506Renderer)) { + // (probably by some internal format conversions), thus using GL_UNSIGNED_BYTE for Adreno + if (!strncmp(gl.renderer, gl.workarounds.adrenoRenderer, 6)) { format = GL_UNSIGNED_BYTE; } else { @@ -2013,8 +2013,8 @@ bool RenderFrame() case 3://0x3 1555 ARGB 16 bit The alpha value is determined by comparison with the value of fb_alpha_threshold. channels = GL_RGBA; // When using RGBA5551 format on Adreno 506, rendering is extremely slow - // (probably by some internal format conversions), thus using GL_UNSIGNED_BYTE - if (!strcmp(renderer, adreno506Renderer)) { + // (probably by some internal format conversions), thus using GL_UNSIGNED_BYTE for Adreno + if (!strncmp(gl.renderer, gl.workarounds.adrenoRenderer, 6)) { format = GL_UNSIGNED_BYTE; } else { diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index e11bde0d9..fe8e2fd9f 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -125,6 +125,11 @@ struct gl_ctx GLuint program,scale,depth_scale; } OSD_SHADER; + struct + { + const char *adrenoRenderer = "Adreno"; + } workarounds; + struct { GLuint geometry,modvols,idxs,idxs2; @@ -135,6 +140,7 @@ struct gl_ctx GLuint fullscreenQuadShader; + const char *renderer; const char *gl_version; const char *glsl_version_header; int gl_major;