Render to texture full multipass support added; RTT stride textures support added
This commit is contained in:
parent
4d39c10c91
commit
e981dd14f8
|
@ -175,8 +175,8 @@ const char* VertexShaderSource =
|
||||||
|
|
||||||
//0 - not in use
|
//0 - not in use
|
||||||
//1 - in use since the last frame
|
//1 - in use since the last frame
|
||||||
//2 - not anymore in use (e.g. exit to menu)
|
|
||||||
u8 rttInUse = 0;
|
u8 rttInUse = 0;
|
||||||
|
u32 rttDepthCounter = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -393,6 +393,10 @@ gl_ctx gl;
|
||||||
int screen_width;
|
int screen_width;
|
||||||
int screen_height;
|
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 (HOST_OS != OS_DARWIN) && !defined(TARGET_NACL32)
|
||||||
#if defined(GLES) && !defined(USE_SDL)
|
#if defined(GLES) && !defined(USE_SDL)
|
||||||
// Create a basic GLES context
|
// Create a basic GLES context
|
||||||
|
@ -1450,7 +1454,7 @@ void OSD_DRAW()
|
||||||
|
|
||||||
bool ProcessFrame(TA_context* ctx)
|
bool ProcessFrame(TA_context* ctx)
|
||||||
{
|
{
|
||||||
if (ctx->rend.isRTT && settings.dreamcast.rttOption == 0)
|
if (ctx->rend.isRTT && settings.dreamcast.rttOption == Disabled)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1582,16 +1586,11 @@ bool RenderFrame()
|
||||||
{
|
{
|
||||||
gcflip=1;
|
gcflip=1;
|
||||||
|
|
||||||
//For some reason this produces wrong results
|
dc_width = FB_W_LINESTRIDE.stride ? FB_W_LINESTRIDE.stride * 4 : FB_X_CLIP.max - FB_X_CLIP.min + 1;
|
||||||
//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;
|
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 scale_x=1, scale_y=1;
|
||||||
|
|
||||||
float scissoring_scale_x = 1;
|
float scissoring_scale_x = 1;
|
||||||
|
|
||||||
if (!is_rtt)
|
if (!is_rtt)
|
||||||
|
@ -1617,8 +1616,6 @@ bool RenderFrame()
|
||||||
dc_width *= scale_x;
|
dc_width *= scale_x;
|
||||||
dc_height *= scale_y;
|
dc_height *= scale_y;
|
||||||
|
|
||||||
glUseProgram(gl.modvol_shader.program);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
float vnear=0;
|
float vnear=0;
|
||||||
|
@ -1646,17 +1643,28 @@ bool RenderFrame()
|
||||||
/*
|
/*
|
||||||
Handle Dc to screen scaling
|
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);
|
if (!is_rtt) {
|
||||||
float ds2s_offs_x = is_rtt ? 0 : ((screen_width - dc2s_scale_h * 640.0) / 2);
|
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
|
//-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[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.scale_coefs[3]=(is_rtt?1:-1);
|
||||||
|
|
||||||
|
|
||||||
ShaderUniforms.depth_coefs[0]=2/(vtx_max_fZ-vtx_min_fZ);
|
ShaderUniforms.depth_coefs[0]=2/(vtx_max_fZ-vtx_min_fZ);
|
||||||
ShaderUniforms.depth_coefs[1]=-vtx_min_fZ-1;
|
ShaderUniforms.depth_coefs[1]=-vtx_min_fZ-1;
|
||||||
ShaderUniforms.depth_coefs[2]=0;
|
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]);
|
//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
|
//VERT and RAM fog color constants
|
||||||
u8* fog_colvert_bgra=(u8*)&FOG_COL_VERT;
|
u8* fog_colvert_bgra=(u8*)&FOG_COL_VERT;
|
||||||
u8* fog_colram_bgra=(u8*)&FOG_COL_RAM;
|
u8* fog_colram_bgra=(u8*)&FOG_COL_RAM;
|
||||||
|
@ -1722,6 +1729,7 @@ bool RenderFrame()
|
||||||
|
|
||||||
ShaderUniforms.Set(s);
|
ShaderUniforms.Set(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
//setup render target first
|
//setup render target first
|
||||||
if (is_rtt)
|
if (is_rtt)
|
||||||
{
|
{
|
||||||
|
@ -1740,7 +1748,7 @@ bool RenderFrame()
|
||||||
|
|
||||||
case 2: //0x2 4444 ARGB 16 bit
|
case 2: //0x2 4444 ARGB 16 bit
|
||||||
channels=GL_RGBA;
|
channels=GL_RGBA;
|
||||||
format=GL_UNSIGNED_SHORT_5_5_5_1;
|
format=GL_UNSIGNED_SHORT_4_4_4_4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3://0x3 1555 ARGB 16 bit The alpha value is determined by comparison with the value of fb_alpha_threshold.
|
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;
|
break;
|
||||||
|
|
||||||
case 4: //0x4 888 RGB 24 bit packed
|
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.
|
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
|
case 6: //0x6 8888 ARGB 32 bit
|
||||||
channels=GL_RGBA;
|
|
||||||
format=GL_UNSIGNED_SHORT_4_4_4_4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 7: //7 invalid
|
case 7: //7 invalid
|
||||||
die("7 is not valid");
|
default:
|
||||||
break;
|
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;
|
rttInUse = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if HOST_OS != OS_DARWIN
|
#if HOST_OS != OS_DARWIN
|
||||||
if (rttInUse == 1) {
|
if (rttInUse == 1) {
|
||||||
ReadRTT();
|
ReadRTT();
|
||||||
rttInUse = 2;
|
rttInUse = 0;
|
||||||
}
|
}
|
||||||
else if (rttInUse == 2) {
|
rttDepthCounter = 0;
|
||||||
FreeRTTBuffers();
|
|
||||||
rttInUse = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER,0);
|
glBindFramebuffer(GL_FRAMEBUFFER,0);
|
||||||
glViewport(0, 0, screen_width, screen_height);
|
glViewport(0, 0, screen_width, screen_height);
|
||||||
|
@ -1840,12 +1838,12 @@ bool RenderFrame()
|
||||||
else
|
else
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
|
||||||
|
|
||||||
//restore scale_x
|
//restore scale_x
|
||||||
scale_x /= scissoring_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();
|
DrawStrips();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,9 +43,21 @@
|
||||||
|
|
||||||
//vertex types
|
//vertex types
|
||||||
extern u32 gcflip;
|
extern u32 gcflip;
|
||||||
|
extern u32 rttDepthCounter;
|
||||||
|
|
||||||
|
extern bool isExtensionSupported(const char *);
|
||||||
|
|
||||||
|
enum rttSelectedOption
|
||||||
|
{
|
||||||
|
Disabled = 0,
|
||||||
|
Zeros,
|
||||||
|
Ones,
|
||||||
|
ShadowCircle,
|
||||||
|
Full
|
||||||
|
};
|
||||||
|
|
||||||
void DrawStrips();
|
void DrawStrips();
|
||||||
|
void checkIfUpdated();
|
||||||
|
|
||||||
struct PipelineShader
|
struct PipelineShader
|
||||||
{
|
{
|
||||||
|
@ -118,7 +130,6 @@ void SortPParams();
|
||||||
|
|
||||||
void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt);
|
void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt);
|
||||||
void ReadRTT();
|
void ReadRTT();
|
||||||
void FreeRTTBuffers();
|
|
||||||
int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
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_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
|
||||||
u32 pp_FogCtrl);
|
u32 pp_FogCtrl);
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#include "gles.h"
|
#include "gles.h"
|
||||||
#include "rend/TexCache.h"
|
#include "rend/TexCache.h"
|
||||||
#include "hw/pvr/pvr_mem.h"
|
#include "hw/pvr/pvr_mem.h"
|
||||||
#include <math.h>
|
#include <cmath>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
|
@ -28,7 +30,7 @@ Compression
|
||||||
const u32 shadowCircleW = 128;
|
const u32 shadowCircleW = 128;
|
||||||
const u32 shadowCircleH = 128;
|
const u32 shadowCircleH = 128;
|
||||||
u16 shadowCircleTexture[shadowCircleW][shadowCircleH] = {0};
|
u16 shadowCircleTexture[shadowCircleW][shadowCircleH] = {0};
|
||||||
u16 buf[1024*1024];
|
set<u32> delayedUpdateQueue;
|
||||||
|
|
||||||
#if FEAT_HAS_SOFTREND
|
#if FEAT_HAS_SOFTREND
|
||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
|
@ -148,7 +150,7 @@ struct TextureCacheData
|
||||||
else {
|
else {
|
||||||
texID = 0;
|
texID = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pData = 0;
|
pData = 0;
|
||||||
tex_type = 0;
|
tex_type = 0;
|
||||||
|
|
||||||
|
@ -232,7 +234,7 @@ struct TextureCacheData
|
||||||
verify(tcw.VQ_Comp==0);
|
verify(tcw.VQ_Comp==0);
|
||||||
//Planar textures support stride selection, mostly used for non power of 2 textures (videos)
|
//Planar textures support stride selection, mostly used for non power of 2 textures (videos)
|
||||||
int stride=w;
|
int stride=w;
|
||||||
if (tcw.StrideSel)
|
if (tcw.StrideSel)
|
||||||
stride=(TEXT_CONTROL&31)*32;
|
stride=(TEXT_CONTROL&31)*32;
|
||||||
//Call the format specific conversion code
|
//Call the format specific conversion code
|
||||||
texconv=tex->PL;
|
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
|
//texture state tracking stuff
|
||||||
Updates++;
|
Updates++;
|
||||||
dirty=0;
|
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
|
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
|
palette_index = indirect_color_ptr; //might be used if pal. tex
|
||||||
vq_codebook=(u8*)&vram[indirect_color_ptr]; //might be used if VQ tex
|
vq_codebook = (u8 *) &vram[indirect_color_ptr]; //might be used if VQ tex
|
||||||
|
|
||||||
//texture conversion work
|
//texture conversion work
|
||||||
PixelBuffer pbt;
|
PixelBuffer pbt;
|
||||||
pbt.p_buffer_start=pbt.p_current_line=temp_tex_buffer;
|
pbt.p_buffer_start=pbt.p_current_line=temp_tex_buffer;
|
||||||
pbt.pixels_per_line=w;
|
|
||||||
|
|
||||||
u32 stride=w;
|
u32 stride=w;
|
||||||
|
|
||||||
|
@ -299,7 +305,15 @@ struct TextureCacheData
|
||||||
|
|
||||||
if(texconv!=0)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -311,13 +325,19 @@ struct TextureCacheData
|
||||||
//PrintTextureName();
|
//PrintTextureName();
|
||||||
|
|
||||||
//lock the texture to detect changes in it
|
//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) {
|
if (texID) {
|
||||||
//upload to OpenGL !
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 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;
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0,comps , w, h, 0, comps, textype, temp_tex_buffer);
|
|
||||||
|
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)
|
if (tcw.MipMapped && settings.rend.UseMipmaps)
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
}
|
}
|
||||||
|
@ -374,7 +394,6 @@ struct TextureCacheData
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <map>
|
|
||||||
map<u64,TextureCacheData> TexCache;
|
map<u64,TextureCacheData> TexCache;
|
||||||
typedef map<u64,TextureCacheData>::iterator TexCacheIter;
|
typedef map<u64,TextureCacheData>::iterator TexCacheIter;
|
||||||
|
|
||||||
|
@ -382,183 +401,302 @@ typedef map<u64,TextureCacheData>::iterator TexCacheIter;
|
||||||
|
|
||||||
struct FBT
|
struct FBT
|
||||||
{
|
{
|
||||||
u32 TexAddr;
|
u32 texAddress;
|
||||||
GLuint depthb,stencilb;
|
u16 texData[1024*1024];
|
||||||
|
GLuint depthb;
|
||||||
GLuint tex;
|
GLuint tex;
|
||||||
|
GLuint renderTex;
|
||||||
GLuint fbo;
|
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 createTexture(u32 w, u32 h, u32 format, u32 type, GLuint & textureID) {
|
||||||
|
glGenTextures(1, &textureID);
|
||||||
void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt)
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
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_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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<u32, FBT> renderedTextures;
|
||||||
|
|
||||||
|
void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt)
|
||||||
|
{
|
||||||
|
FBT *renderedTexture;
|
||||||
|
u32 location = addy >> 3;
|
||||||
|
map<u32, FBT>::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
|
// Create the object that will allow us to render to the aforementioned texture
|
||||||
if (!rv.fbo)
|
if (!renderedTexture->fbo) {
|
||||||
glGenFramebuffers(1, &rv.fbo);
|
glGenFramebuffers(1, &renderedTexture->fbo);
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, rv.fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, renderedTexture->fbo);
|
||||||
|
|
||||||
// Attach the texture to the FBO
|
// Attach the texture to the FBO
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rv.tex, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture->renderTex, 0);
|
||||||
|
|
||||||
// Attach the depth buffer we created earlier to our FBO.
|
// Attach the depth buffer we created earlier to our FBO.
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rv.depthb);
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderedTexture->depthb);
|
||||||
|
|
||||||
// Check that our FBO creation was successful
|
// Check that our FBO creation was successful
|
||||||
GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
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);
|
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) {
|
u16 *dataPointer = fbt.texData;
|
||||||
//currently RGB 565 is supported only
|
const u32 kval_upper_bit = fbt.kval_bit;
|
||||||
case 1: //0x1 565 RGB 16 bit
|
const u32 fb_alpha_threshold = fbt.fb_alpha_threshold;
|
||||||
{
|
|
||||||
u16 *dataPointer = temp_tex_buffer;
|
switch (fbt.fb_packmode) {
|
||||||
glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, temp_tex_buffer);
|
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++)
|
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++;
|
*dataPointer++;
|
||||||
}
|
}
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, buf);
|
|
||||||
|
|
||||||
break;
|
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:
|
default:
|
||||||
//clear unsupported texture to avoid artifacts
|
//clear unsupported texture to avoid artifacts
|
||||||
memset(buf, '\0', w * h);
|
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, buf);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, temp_tex_buffer);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadRTT()
|
void ReadRTT()
|
||||||
{
|
{
|
||||||
FBT& rv=fb_rtt;
|
map<u32, FBT>::iterator it;
|
||||||
|
|
||||||
//get viewport width and height from rtt framebuffer
|
for ( it = renderedTextures.begin(); it != renderedTextures.end(); it++ )
|
||||||
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,
|
if(!it->second.updated) {
|
||||||
GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, shadowCircleTexture[0]);
|
continue;
|
||||||
}
|
}
|
||||||
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);
|
GLint w = it->second.w;
|
||||||
}
|
GLint h = it->second.h;
|
||||||
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);
|
if (settings.dreamcast.rttOption == ShadowCircle)
|
||||||
}
|
{
|
||||||
else if (settings.dreamcast.rttOption == 4)
|
glBindTexture(GL_TEXTURE_2D, it->second.tex);
|
||||||
{
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadowCircleW, shadowCircleH, 0,
|
||||||
handlePackModeRTT(w, h);
|
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()
|
void checkIfUpdated() {
|
||||||
{
|
if(!pvrrc.isRTT && delayedUpdateQueue.size())
|
||||||
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; }
|
for (set<u32>::iterator it=delayedUpdateQueue.begin(); it != delayedUpdateQueue.end(); ++it) {
|
||||||
if (fb_rtt.depthb) { glDeleteRenderbuffers(1,&fb_rtt.depthb); fb_rtt.depthb = 0; }
|
//We can directly read because this address exists already
|
||||||
if (fb_rtt.stencilb) { glDeleteRenderbuffers(1,&fb_rtt.stencilb); fb_rtt.stencilb = 0; }
|
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)
|
void initializeRttTexture(const TSP & tsp, const TCW & tcw, FBT * tempRenderedTexture) {
|
||||||
{
|
if (!tempRenderedTexture->initialized)
|
||||||
if (tcw.TexAddr==fb_rtt.TexAddr && fb_rtt.tex)
|
|
||||||
{
|
{
|
||||||
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<u32, FBT>::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
|
//lookup texture
|
||||||
TextureCacheData* tf;
|
TextureCacheData *tf;
|
||||||
//= TexCache.Find(tcw.full,tsp.full);
|
//= 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())
|
if (tx != TexCache.end()) {
|
||||||
{
|
tf = &tx->second;
|
||||||
tf=&tx->second;
|
|
||||||
}
|
}
|
||||||
else //create if not existing
|
else //create if not existing
|
||||||
{
|
{
|
||||||
TextureCacheData tfc={0};
|
TextureCacheData tfc = {0};
|
||||||
TexCache[key]=tfc;
|
TexCache[key] = tfc;
|
||||||
|
|
||||||
tx=TexCache.find(key);
|
tx = TexCache.find(key);
|
||||||
tf=&tx->second;
|
tf = &tx->second;
|
||||||
|
|
||||||
|
tf->tsp = tsp;
|
||||||
|
tf->tcw = tcw;
|
||||||
|
|
||||||
tf->tsp=tsp;
|
|
||||||
tf->tcw=tcw;
|
|
||||||
tf->Create(true);
|
tf->Create(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//update if needed
|
//update if needed
|
||||||
if (tf->NeedsUpdate())
|
if (tf->NeedsUpdate()) {
|
||||||
tf->Update();
|
tf->Update();
|
||||||
|
}
|
||||||
|
|
||||||
//update state for opts/stuff
|
//update state for opts/stuff
|
||||||
tf->Lookups++;
|
tf->Lookups++;
|
||||||
|
@ -567,7 +705,6 @@ GLuint gl_GetTexture(TSP tsp, TCW tcw)
|
||||||
return tf->texID;
|
return tf->texID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
text_info raw_GetTexture(TSP tsp, TCW tcw)
|
text_info raw_GetTexture(TSP tsp, TCW tcw)
|
||||||
{
|
{
|
||||||
text_info rv = { 0 };
|
text_info rv = { 0 };
|
||||||
|
@ -609,7 +746,6 @@ text_info raw_GetTexture(TSP tsp, TCW tcw)
|
||||||
rv.pdata = tf->pData;
|
rv.pdata = tf->pData;
|
||||||
rv.textype = tf->tex_type;
|
rv.textype = tf->tex_type;
|
||||||
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,7 +767,6 @@ void CollectCleanup() {
|
||||||
for (size_t i=0; i<list.size(); i++) {
|
for (size_t i=0; i<list.size(); i++) {
|
||||||
//printf("Deleting %d\n",TexCache[list[i]].texID);
|
//printf("Deleting %d\n",TexCache[list[i]].texID);
|
||||||
TexCache[list[i]].Delete();
|
TexCache[list[i]].Delete();
|
||||||
|
|
||||||
TexCache.erase(list[i]);
|
TexCache.erase(list[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -643,7 +778,7 @@ void DoCleanup() {
|
||||||
void InitShadowCircle() {
|
void InitShadowCircle() {
|
||||||
s32 middle_x = shadowCircleW / 2;
|
s32 middle_x = shadowCircleW / 2;
|
||||||
s32 middle_y = shadowCircleH / 2;
|
s32 middle_y = shadowCircleH / 2;
|
||||||
u32 radius = 15;
|
u32 radius = 25;
|
||||||
|
|
||||||
s32 x = 0, y = 0;
|
s32 x = 0, y = 0;
|
||||||
for (s32 i = 0; i <= 360; i = i + 2) {
|
for (s32 i = 0; i <= 360; i = i + 2) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class Emulator extends Application {
|
||||||
public static int cable = 3;
|
public static int cable = 3;
|
||||||
public static int dcregion = 3;
|
public static int dcregion = 3;
|
||||||
public static int broadcast = 4;
|
public static int broadcast = 4;
|
||||||
public static int rtt = 3;
|
public static int rtt = 1;
|
||||||
public static boolean limitfps = true;
|
public static boolean limitfps = true;
|
||||||
public static boolean nobatch = false;
|
public static boolean nobatch = false;
|
||||||
public static boolean nosound = false;
|
public static boolean nosound = false;
|
||||||
|
|
|
@ -747,7 +747,7 @@ public class OptionsFragment extends Fragment {
|
||||||
Emulator.cable = 3;
|
Emulator.cable = 3;
|
||||||
Emulator.dcregion = 3;
|
Emulator.dcregion = 3;
|
||||||
Emulator.broadcast = 4;
|
Emulator.broadcast = 4;
|
||||||
Emulator.rtt = 3;
|
Emulator.rtt = 1;
|
||||||
Emulator.limitfps = true;
|
Emulator.limitfps = true;
|
||||||
Emulator.mipmaps = true;
|
Emulator.mipmaps = true;
|
||||||
Emulator.widescreen = false;
|
Emulator.widescreen = false;
|
||||||
|
|
Loading…
Reference in New Issue