Path: blob/master/libmupen64plus/mupen64plus-video-z64/src/rgl.cpp
2 views
/*1* z642*3* Copyright (C) 2007 ziggy4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License along16* with this program; if not, write to the Free Software Foundation, Inc.,17* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.18*19**/2021/*22*23* TODO24*25* - hires framebuffer : scale them accordingly to the GL screen resolution26*27* - multitexturing avec tilenum == 7, ca marche comment ?28* --> tilenum=7 should be translated to tilenum=0 for triangle and texrec primitives29*30* - CvgXAlpha mode not really correct, effect probably depends on the texture format31* --> apparently fixed, Intensity textures shouldn't be affected by this effect32* --> correction : it had nothing to do with the texture format, but with33* the alpha_cvg_select flag34*35* - fix fbo depth clear in LEGO racer (also affects beetle and reflection in rally 99)36* (also affects Zelda OOT subscreen)37* --> DONE38*39* - frame buffer ordering (LEGO racer)40* --> DONE but required also less conservative framebuffer check41*42* - format conversion for hires framebuffers when required (CBFD , Banjo)43* --> DONE (quick hack)44*45* - some texture (4 ? 8 bits ?) problems46* --> either they're fixed, either I forgot which problem it was47*48* - mirrored textures49* --> done but rely on a GL extension, do we care ?50*51* - better blend52* --> mostly done slow way, now need to implement the quick way53* --> done faster way, seems to work reasonably well54*55* - need to sort out combiner clamp modes56* --> started but not complete57* --> the problem is much more complicated, it's not combiner clamping58* but coverage calculation modes.59*60* - fog !!61* --> done62*63* PROBLEMS64*65* - this list needs to be updated :)66* - links not always rendered in the subscreen67* --> depth clear problem, anything else ? FIXED68* - texture problems in beetle69* --> mostly fixed, it was multitexturing, the sky still has a weird problem though70* --> completely fixed at last (the sky uses tex2 in the second combiner cycle,71* which should be interpreted as tex1 (apparently tex2 isn't available in the72* second cycle)73* UPDATE : in fact tex1 and tex2 need to be swapped in the second step of74* the combiner, weird but it fixes a few other problems as well75*76**/7778#include "rdp.h"79#include "rgl.h"8081#include <SDL.h>8283//#define NOFBO84#define ZTEX85#define FBORGBA8687rglTexCache_t rglTexCache[0x1000];88uint8_t rglTmpTex[1024*1024*4];89uint8_t rglTmpTex2[1024*1024*4];9091volatile int rglStatus, rglNextStatus;9293static int wireframe;9495static uint32_t old_vi_origin;9697int rglFrameCounter;9899extern int viewportOffset;100rglSettings_t rglSettings;101102rglDepthBuffer_t zBuffers[MAX_DEPTH_BUFFERS];103int nbZBuffers;104105rglRenderBuffer_t rBuffers[MAX_RENDER_BUFFERS];106int nbRBuffers;107rglRenderBuffer_t * curRBuffer;108rglRenderBuffer_t * curZBuffer;109rglRenderBufferHead_t rBufferHead;110111int rglTexCacheCounter = 1;112113rglTexture_t rglTextures[RGL_TEX_CACHE_SIZE];114115rglRenderChunk_t chunks[MAX_RENDER_CHUNKS];116rglRenderChunk_t * curChunk;117int nbChunks, renderedChunks;118119rglStrip_t strips[MAX_STRIPS];120rglVertex_t vtxs[6*MAX_STRIPS];121int nbStrips, nbVtxs;122123rglRenderMode_t renderModesDb[MAX_RENDER_MODES];124int nbRenderModes;125126rglShader_t * rglCopyShader;127rglShader_t * rglCopyDepthShader;128129int rglScreenWidth = 320, rglScreenHeight = 240;130131#define CHECK_FRAMEBUFFER_STATUS() \132{\133GLenum status; \134status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); \135/*LOGERROR("%x\n", status);*/\136switch(status) { \137case GL_FRAMEBUFFER_COMPLETE_EXT: \138/*LOGERROR("framebuffer complete!\n");*/\139break; \140case GL_FRAMEBUFFER_UNSUPPORTED_EXT: \141LOGERROR("framebuffer GL_FRAMEBUFFER_UNSUPPORTED_EXT\n");\142/* you gotta choose different formats */ \143/*rglAssert(0);*/ \144break; \145case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: \146LOGERROR("framebuffer INCOMPLETE_ATTACHMENT\n");\147break; \148case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: \149LOGERROR("framebuffer FRAMEBUFFER_MISSING_ATTACHMENT\n");\150break; \151case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: \152LOGERROR("framebuffer FRAMEBUFFER_DIMENSIONS\n");\153break; \154case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: \155LOGERROR("framebuffer INCOMPLETE_FORMATS\n");\156break; \157case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: \158LOGERROR("framebuffer INCOMPLETE_DRAW_BUFFER\n");\159break; \160case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: \161LOGERROR("framebuffer INCOMPLETE_READ_BUFFER\n");\162break; \163case GL_FRAMEBUFFER_BINDING_EXT: \164LOGERROR("framebuffer BINDING_EXT\n");\165break; \166default: \167LOGERROR("framebuffer generic error\n");\168break; \169/* programming error; will fail on all hardware */ \170/*rglAssert(0);*/ \171}\172}173/*174case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: \175LOGERROR("framebuffer INCOMPLETE_DUPLICATE_ATTACHMENT\n");\176break; \177*/178179rglDepthBuffer_t * rglFindDepthBuffer(uint32_t address, int width, int height)180{181int i;182rglDepthBuffer_t * buffer;183for (i=0; i<nbZBuffers; i++)184if (zBuffers[i].address == address &&185zBuffers[i].width == width &&186zBuffers[i].height == height)187return zBuffers+i;188189rglAssert(nbZBuffers < MAX_DEPTH_BUFFERS);190buffer = zBuffers + nbZBuffers++;191192LOG("Creating depth buffer %x %d x %d\n", address, width, height);193194buffer->address = address;195buffer->width = width;196buffer->height = height;197198// glGenRenderbuffersEXT(1, &buffer->zbid);199// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buffer->zbid);200// rglAssert(glGetError() == GL_NO_ERROR);201// glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,202// buffer->width, buffer->height);203// rglAssert(glGetError() == GL_NO_ERROR);204205#ifdef ZTEX206glGenTextures(1, &buffer->zbid);207rglAssert(glGetError() == GL_NO_ERROR);208glBindTexture(GL_TEXTURE_2D, buffer->zbid);209rglAssert(glGetError() == GL_NO_ERROR);210glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,211buffer->width, buffer->height, 0,212GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);213rglAssert(glGetError() == GL_NO_ERROR);214glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);215glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);216glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);217glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);218glBindTexture(GL_TEXTURE_2D, 0);219#else220glGenRenderbuffersEXT(1, &buffer->zbid);221glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buffer->zbid);222glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,223buffer->width, buffer->height);224225#endif226227return buffer;228}229230void rglDeleteRenderBuffer(rglRenderBuffer_t & buffer)231{232buffer.mod.xl = buffer.mod.yl = 0;233buffer.mod.xh = buffer.mod.yh = 8192;234buffer.depthBuffer = 0;235#ifndef NOFBO236if (buffer.fbid) {237glDeleteFramebuffersEXT(1, &buffer.fbid);238buffer.fbid = 0;239}240if (buffer.texid) {241glDeleteTextures(1, &buffer.texid);242buffer.texid = 0;243}244buffer.nbDepthSections = 0;245#ifdef RGL_EXACT_BLEND246glDeleteFramebuffersEXT(1, &buffer.fbid2);247buffer.fbid2 = 0;248glDeleteTextures(1, &buffer.texid2);249buffer.texid2 = 0;250#endif251#endif252}253254void rglFullSync()255{256if (rglSettings.forceSwap)257// hack for starwars, perfect dark subscreen to prevent filling up our chunk table258old_vi_origin = ~0;259}260261// note : if "same" is 1 then both tiles use the same texture, in this262// case we can't safely modify the clamping mode263void rglFixupMapping(rglStrip_t & strip, rglTile_t & tile,264float ds, float dt, float ss, float st,265float & dsm, float & dtm, int same)266{267float mins = strip.vtxs[0].s;268float mint = strip.vtxs[0].t;269int i;270if ( (tile.mask_s && !tile.cs) || (tile.mask_t && !tile.ct) )271for (i=1; i<strip.nbVtxs; i++) {272if (strip.vtxs[i].s < mins)273mins = strip.vtxs[i].s;274if (strip.vtxs[i].t < mint)275mint = strip.vtxs[i].t;276}277if (tile.mask_s && !tile.cs)278dsm = -((int(mins+0.5f - tile.sl*float(1<<(tile.shift_s+4))/64.0f) + (tile.ms<<tile.mask_s)) & ((~tile.ms)<<(tile.mask_s+tile.shift_s+4)>>4));279else280dsm = 0;281if (tile.mask_t && !tile.ct)282dtm = -((int(mint+0.5f - tile.tl*float(1<<(tile.shift_t+4))/64.0f) + (tile.mt<<tile.mask_t)) & ((~tile.mt)<<(tile.mask_t+tile.shift_t+4)>>4));283else284dtm = 0;285286if (rglSettings.hiresFb && tile.hiresBuffer)287return;288else {289GLuint wws = tile.ws, wwt = tile.wt;290291if (same || wws != GL_REPEAT)292goto skips;293for (i=0; i<strip.nbVtxs; i++) {294float a = (strip.vtxs[i].s + ds + dsm);295if ((a-0.5f)/ss > 1 || (a+0.5f)/ss < 0) {296goto skips;297}298}299//LOG("fixing S clamp\n");300wws = GL_CLAMP_TO_EDGE;301skips:302if (tile.tex->ws != wws) {303glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wws);304tile.tex->ws = wws;305}306307if (same || wwt != GL_REPEAT)308goto skipt;309for (i=0; i<strip.nbVtxs; i++) {310float a = (strip.vtxs[i].t + dt + dtm);311if ((a-0.5f)/st > 1 || (a+0.5f)/st < 0)312goto skipt;313}314//LOG("fixing T clamp\n");315wwt = GL_CLAMP_TO_EDGE;316skipt:317if (tile.tex->wt != wwt) {318glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wwt);319tile.tex->wt = wwt;320}321}322}323324int rglUseTile(rglTile_t & tile, float & ds, float & dt, float & ss, float & st)325{326int res = 0;327ds = -tile.sl*float(1<<(tile.shift_s+4))/64.0f;328dt = -tile.tl*float(1<<(tile.shift_t+4))/64.0f;329if (rglSettings.hiresFb && tile.hiresBuffer) {330rglRenderBuffer_t & hbuf = *tile.hiresBuffer;331// if (hbuf.flags & RGL_RB_DEPTH) {332// glBindTexture(GL_TEXTURE_2D, hbuf.depthBuffer->zbid);333// res = RGL_COMB_IN0_DEPTH;334// } else335glBindTexture(GL_TEXTURE_2D, hbuf.texid);336rglAssert(glGetError() == GL_NO_ERROR);337ss = -(hbuf.width<<(tile.shift_s+4)>>4);338st = -(hbuf.height<<(tile.shift_t+4)>>4);339ds = -ds - (((int32_t(tile.hiresAddress) - int32_t(hbuf.addressStart)) % hbuf.line) >> hbuf.size << 1);340dt = -dt - (int32_t(tile.hiresAddress) - int32_t(hbuf.addressStart)) / hbuf.line;341ss /= float(hbuf.realWidth)/hbuf.fboWidth;342st /= float(hbuf.realHeight)/hbuf.fboHeight;343ds = ss - ds;344dt = st - dt;345346DUMP("texture fb %p shift %g x %g (scale %g x %g) tile %d x %d (sl %d tl %d)\n",347&hbuf, ds, dt, ss, st, tile.w, tile.h,348tile.sl, tile.tl);349} else {350glBindTexture(GL_TEXTURE_2D, tile.tex->id);351rglAssert(glGetError() == GL_NO_ERROR);352ss = tile.w<<(tile.shift_s+4)>>4; st = tile.h<<(tile.shift_t+4)>>4;353354if (tile.tex->filter != tile.filter) {355glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tile.filter);356glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tile.filter);357rglAssert(glGetError() == GL_NO_ERROR);358tile.tex->filter = tile.filter;359}360}361return res;362}363364void rglPrepareFramebuffer(rglRenderBuffer_t & buffer)365{366//int olderased = buffer.flags & RGL_RB_ERASED;367368if (buffer.area.xh == 8192)369return;370371GLuint restoreId = 0, restoreFbid = 0;372float d2 = -1;373float d = 0;374float restoreW = buffer.width+d2, restoreH = buffer.height+d2;375int w, h;376restoreW *= float(buffer.fboWidth+d) / (buffer.realWidth+d);377restoreH *= float(buffer.fboHeight+d) / (buffer.realHeight+d);378379buffer.flags &= ~RGL_RB_ERASED;380381// buffer.width = ((buffer.area.xl - buffer.area.xh >>2) + 15)&~15;382// buffer.height = ((buffer.area.yl - buffer.area.yh >>2) + 15)&~15;383// buffer.width = ((buffer.area.xl >>2) + 3)&~3;384// buffer.height = ((buffer.area.yl >>2) + 3)&~3;385//buffer.width = ((buffer.area.xl >>2))&~7;386buffer.width = buffer.fbWidth;387//buffer.height = ((buffer.area.yl >>2))&~7;388buffer.height = ((buffer.area.yl >>2));389if (!buffer.width) buffer.width = 1;390if (!buffer.height) buffer.height = 1;391392buffer.addressStop = buffer.addressStart + buffer.line * ((buffer.area.yl >>2)+1);393394if (rglSettings.lowres) {395buffer.realWidth = buffer.width;396buffer.realHeight = buffer.height;397} else {398if (buffer.width <= 128 || buffer.height <= 128) {399buffer.realWidth = buffer.width*4;400buffer.realHeight = buffer.height*4;401buffer.flags &= ~RGL_RB_FULL;402} else {403buffer.realWidth = screen_width * buffer.width / rglScreenWidth;404buffer.realHeight = screen_height * buffer.height / rglScreenHeight;405// buffer.realWidth = screen_width * buffer.width / vi_width;406// if (buffer.height > 250)407// buffer.realHeight = screen_height * buffer.height / 480;408// else409// buffer.realHeight = screen_height * buffer.height / 240;410buffer.flags |= RGL_RB_FULL;411}412}413414if (rglSettings.noNpotFbos) {415w = 1; h = 1;416while (w < buffer.realWidth) w <<= 1;417while (h < buffer.realHeight) h <<= 1;418} else {419w = buffer.realWidth;420h = buffer.realHeight;421}422423#ifndef NOFBO424if (buffer.fboWidth == w && buffer.fboHeight == h)425buffer.redimensionStamp = rglFrameCounter;426427if (buffer.fbid &&428(//buffer.fboWidth < w || buffer.fboHeight < h ||429(rglFrameCounter - buffer.redimensionStamp > 4))) {430LOG("Redimensionning buffer\n");431restoreId = buffer.texid;432restoreFbid = buffer.fbid;433buffer.texid = buffer.fbid = 0;434rglDeleteRenderBuffer(buffer);435}436437DUMP("Render buffer %p at %x --> %x\n", &buffer,438buffer.addressStart, buffer.addressStop);439440if (!buffer.fbid) {441int glfmt;442switch (buffer.format) {443// case RDP_FORMAT_I:444// case RDP_FORMAT_CI:445// glfmt = GL_LUMINANCE;446// break;447default:448#ifdef FBORGBA449glfmt = GL_RGBA;450#else451glfmt = GL_RGB;452#endif453}454455LOG("creating fbo %x %dx%d (%dx%d) fmt %x\n", buffer.addressStart, buffer.width, buffer.height, w, h, buffer.format);456457buffer.fboWidth = w;458buffer.fboHeight = h;459460#ifdef RGL_EXACT_BLEND461glGenFramebuffersEXT(1, &buffer.fbid2);462rglAssert(glGetError() == GL_NO_ERROR);463glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid2);464465// FIXME we should not need to allocate a color texture for depth only rendering466if (1||!(buffer.flags & RGL_RB_DEPTH)) {467glGenTextures(1, &buffer.texid2);468rglAssert(glGetError() == GL_NO_ERROR);469glBindTexture(GL_TEXTURE_2D, buffer.texid2);470rglAssert(glGetError() == GL_NO_ERROR);471glTexImage2D(GL_TEXTURE_2D, 0, glfmt, w, h, 0,472glfmt, GL_UNSIGNED_BYTE, NULL);473rglAssert(glGetError() == GL_NO_ERROR);474glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);475glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);476477// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);478// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);479480rglAssert(glGetError() == GL_NO_ERROR);481glBindTexture(GL_TEXTURE_2D, 0);482glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,483GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,484buffer.texid2, 0);485}486#endif487488if (restoreId) {489buffer.fbid = restoreFbid;490} else {491glGenFramebuffersEXT(1, &buffer.fbid);492rglAssert(glGetError() == GL_NO_ERROR);493}494glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid);495496// FIXME we should not need to allocate a color texture for depth only rendering497if (1||!(buffer.flags & RGL_RB_DEPTH)) {498glGenTextures(1, &buffer.texid);499rglAssert(glGetError() == GL_NO_ERROR);500glBindTexture(GL_TEXTURE_2D, buffer.texid);501rglAssert(glGetError() == GL_NO_ERROR);502glTexImage2D(GL_TEXTURE_2D, 0, glfmt, w, h, 0,503glfmt, GL_UNSIGNED_BYTE, NULL);504rglAssert(glGetError() == GL_NO_ERROR);505glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);506glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);507glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);508glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);509510// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);511// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);512513rglAssert(glGetError() == GL_NO_ERROR);514glBindTexture(GL_TEXTURE_2D, 0);515glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,516GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,517buffer.texid, 0);518519glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0 );520521if (!restoreId) {522glClearColor(0, 0, 0, 1);523glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);524glClear(GL_COLOR_BUFFER_BIT);525} else {526glViewport(0, 0, buffer.realWidth, buffer.realHeight);527glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);528glDisable(GL_DEPTH_TEST);529glBindTexture(GL_TEXTURE_2D, restoreId);530rglUseShader(rglCopyShader);531glBegin(GL_TRIANGLE_STRIP);532glTexCoord2f((buffer.width+d2)/restoreW, 0); glVertex2f(1, 0);533glTexCoord2f(0, 0); glVertex2f(0, 0);534glTexCoord2f((buffer.width+d2)/restoreW, (buffer.height+d2)/restoreH); glVertex2f(1, 1);535glTexCoord2f(0, (buffer.height+d2)/restoreH); glVertex2f(0, 1);536glEnd();537glDeleteTextures(1, &restoreId);538}539}540} else541glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid);542#endif543544rglAssert(glGetError() == GL_NO_ERROR);545546// hack for LEGO racer, real fix coming soon547// if (olderased)548// {549// glDepthMask(GL_TRUE);550// glClearDepth(1);551// glClear(GL_DEPTH_BUFFER_BIT);552// }553}554555void rglRenderChunks(rglRenderBuffer_t * upto)556{557if (upto->area.xh != 8192 && renderedChunks < upto->chunkId)558rglRenderChunks(upto->chunkId);559}560561void rglRenderChunks(int upto)562{563int i;564//printf("vi_origin %x nbChunks %d\n", vi_origin, nbChunks);565rglRenderBuffer_t * lastBuffer = 0;566uint32_t lastDepthAddress = ~0;567float zb = 0.0f;568569DUMP("rendering chunks upto %d / %d\n", upto, nbChunks);570571glEnable(GL_SCISSOR_TEST);572for (i=renderedChunks; i<upto; i++) {573int j;574rglRenderChunk_t & chunk = chunks[i];575576if (chunk.renderBuffer->nbDepthSections) {577// reselect the renderbuffer with correct width (needed by LEGO racer,578// because they clear a 320x240 depth buffer to render in small 64x64 framebuffer)579// and adjust the area to the associated color buffer580// no need to optimize this search because it's rare (i.e. mainly depth clear,581// so once per frame)582for (j=chunk.renderBuffer->nbDepthSections-1; j>=0; j--) {583// LOG("j %d %d %d %d\n", j, i, chunk.renderBuffer->depthSections[j].chunkId,584// chunk.renderBuffer->depthSections[j].buffer - rBuffers);585if (i >= chunk.renderBuffer->depthSections[j].chunkId)586break;587}588//rglAssert(j < chunk.renderBuffer->nbDepthSections-1);589if (j < chunk.renderBuffer->nbDepthSections-1) {590rglRenderBuffer_t * cbuffer = chunk.renderBuffer->depthSections[j+1].buffer;591chunk.renderBuffer = rglSelectRenderBuffer(chunk.renderBuffer->addressStart, cbuffer->fbWidth, chunk.renderBuffer->size, chunk.renderBuffer->format);592chunk.renderBuffer->area = cbuffer->area;593chunk.renderBuffer->flags |= RGL_RB_DEPTH;594}595}596597rglRenderBuffer_t & buffer = *chunk.renderBuffer;598int oldFlags = ~0;599int oldTilenum = ~0;600int combFormat = 0;601602rglAssert(buffer.area.xh != 8192);603604if (lastBuffer != &buffer)605rglPrepareFramebuffer(buffer);606607DUMP("Buffer %p at %x area %d -> %d x %d -> %d\n",608&buffer, buffer.addressStart,609buffer.area.xh>>2, buffer.area.xl>>2,610buffer.area.yh>>2, buffer.area.yl>>2);611// if (buffer.addressStart != vi_origin)612// continue;613614if (buffer.flags & RGL_RB_DEPTH)615chunk.depthAddress = buffer.addressStart;616617if (lastBuffer != &buffer ||618lastDepthAddress != chunk.depthAddress) {619lastBuffer = &buffer;620lastDepthAddress = chunk.depthAddress;621int j;622for (j=0; j<nbRBuffers; j++) {623int overlap = int(rBuffers[j].addressStop) - int(buffer.addressStart);624if (int(buffer.addressStop) - int(rBuffers[j].addressStart) < overlap)625overlap = int(buffer.addressStop) - int(rBuffers[j].addressStart);626// LOG("checking #%d %x --> %x with %x --> %x overlap %x\n",627// j,628// rBuffers[j].addressStart, rBuffers[j].addressStop,629// buffer.addressStart, buffer.addressStop,630// overlap);631// check if more than 10% of the buffer was erased632if (rBuffers+j != &buffer &&633overlap > int(rBuffers[j].addressStop - rBuffers[j].addressStart)/10634// rBuffers[j].addressStop > buffer.addressStart &&635// rBuffers[j].addressStart < buffer.addressStop636) {637rBuffers[j].flags |= RGL_RB_ERASED;638DUMP("erasing fb #%d\n", j);639}640}641642#ifndef NOFBO643glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid);644645rglDepthBuffer_t * zbuf = rglFindDepthBuffer(chunk.depthAddress,646buffer.fboWidth, buffer.fboHeight);647if (zbuf != buffer.depthBuffer) {648buffer.depthBuffer = zbuf;649#ifdef ZTEX650glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,651GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D,652buffer.depthBuffer->zbid, 0);653#else654glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, buffer.depthBuffer->zbid );655#endif656// glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,657// GL_RENDERBUFFER_EXT, depthBuffer->zbid );658659CHECK_FRAMEBUFFER_STATUS();660}661#endif662663glViewport(0, 0, buffer.realWidth, buffer.realHeight);664}665666if (chunk.rdpState.clip.yl < chunk.rdpState.clip.yh ||667chunk.rdpState.clip.xl < chunk.rdpState.clip.xh)668continue;669670glScissor((chunk.rdpState.clip.xh >>2)*buffer.realWidth/buffer.width,671(chunk.rdpState.clip.yh >>2)*buffer.realHeight/buffer.height,672((chunk.rdpState.clip.xl-chunk.rdpState.clip.xh) >>2)*buffer.realWidth/buffer.width,673((chunk.rdpState.clip.yl-chunk.rdpState.clip.yh) >>2)*buffer.realHeight/buffer.height);674rglAssert(glGetError() == GL_NO_ERROR);675676#ifndef NOFBO677#ifdef RGL_EXACT_BLEND678glPushAttrib(GL_ALL_ATTRIB_BITS);679glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid2);680glBindTexture(GL_TEXTURE_2D, buffer.texid);681glEnable(GL_TEXTURE_2D);682rglUseShader(rglCopyShader);683glColor4ub(255,255,255,255);684glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);685glDisable(GL_DEPTH_TEST);686687for (j=0; j<chunk.nbStrips; j++) {688rglStrip_t & strip = chunk.strips[j];689int k;690691glBegin(GL_TRIANGLE_STRIP);692for (k=0; k<strip.nbVtxs; k++) {693glTexCoord2f((strip.vtxs[k].x/(buffer.width)),694(strip.vtxs[k].y/(buffer.height)));695glVertex2f((strip.vtxs[k].x/(buffer.width)),696(strip.vtxs[k].y/(buffer.height)));697}698glEnd();699}700glBindTexture(GL_TEXTURE_2D, 0);701glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, buffer.fbid);702glPopAttrib();703#endif704#endif705706if (buffer.flags & RGL_RB_DEPTH) {707DUMP("depth write\n");708//rglRenderMode(chunk);709glDepthMask(GL_TRUE);710glDepthFunc(GL_ALWAYS);711glDisable( GL_ALPHA_TEST );712glDisable( GL_POLYGON_OFFSET_FILL ); // ?713//glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);714} else {715rglRenderMode(chunk);716}717rglAssert(glGetError() == GL_NO_ERROR);718719if (RDP_GETOM_Z_MODE(chunk.rdpState.otherModes) & 1) {720switch(RDP_GETOM_Z_MODE(chunk.rdpState.otherModes)) {721case 3:722zb = 20;723break;724default:725zb = 4;726break;727}728} else {729zb = 0;730}731zb *= 16e-6f;732733#ifdef RGL_EXACT_BLEND734glDisable(GL_BLEND);735glActiveTextureARB(GL_TEXTURE1_ARB);736glBindTexture(GL_TEXTURE_2D, buffer.texid2);737glEnable(GL_TEXTURE_2D);738rglAssert(glGetError() == GL_NO_ERROR);739glActiveTextureARB(GL_TEXTURE0_ARB);740#endif741742combFormat = (buffer.size == 1? RGL_COMB_FMT_I : RGL_COMB_FMT_RGBA);743// not yet744// if (buffer.flags & RGL_RB_DEPTH)745// combFormat = RGL_COMB_FMT_DEPTH;746747float ds[2], dt[2], ss[2], st[2];748float dsm[2], dtm[2];749for (j=0; j<chunk.nbStrips; j++) {750rglStrip_t & strip = chunk.strips[j];751int k;752int tilenum = strip.tilenum;753if (tilenum == 7 && RDP_GETOM_CYCLE_TYPE(chunk.rdpState.otherModes)==1) {754tilenum = 0;755combFormat |= RGL_COMB_TILE7;756}757758rglTile_t & tile = chunk.tiles[tilenum];759rglTile_t & tile2 = chunk.tiles[tilenum+1];760761if (strip.flags != oldFlags || tilenum != oldTilenum) {762oldTilenum = tilenum;763if (strip.flags & RGL_STRIP_TEX1) {764//if (tile.hiresBuffer) continue;765combFormat |= rglUseTile(tile, ds[0], dt[0], ss[0], st[0]);766glEnable(GL_TEXTURE_2D);767} else768glDisable(GL_TEXTURE_2D);769770glActiveTextureARB(GL_TEXTURE2_ARB);771if (strip.flags & RGL_STRIP_TEX2) {772//if (tile2.hiresBuffer) continue;773combFormat |= rglUseTile(tile2, ds[1], dt[1], ss[1], st[1]) << 1;774glEnable(GL_TEXTURE_2D);775} else776glDisable(GL_TEXTURE_2D);777glActiveTextureARB(GL_TEXTURE0_ARB);778}779780if (j == 0)781rglSetCombiner(chunk, combFormat);782783if (strip.flags != oldFlags) {784oldFlags = strip.flags;785if (strip.flags & RGL_STRIP_ZBUFFER)786glEnable(GL_DEPTH_TEST);787else788glDisable(GL_DEPTH_TEST);789790if (!(strip.flags & RGL_STRIP_SHADE))791// TODO take in account the framebuffer size (16b or 32b)792glColor4f(RDP_GETC16_R(chunk.rdpState.fillColor)/31.0f,793RDP_GETC16_G(chunk.rdpState.fillColor)/31.0f,794RDP_GETC16_B(chunk.rdpState.fillColor)/31.0f,795RDP_GETC16_A(chunk.rdpState.fillColor));796797if (wireframe) {798if (!(strip.flags & (RGL_STRIP_SHADE | RGL_STRIP_TEX1 | RGL_STRIP_TEX2)))799glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);800else801glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);802}803}804805// FIXME806// if (RDP_GETOM_CYCLE_TYPE(curChunk->rdpState.otherModes) < 2)807// glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);808// else809// glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);810811812if (strip.flags & RGL_STRIP_TEX1)813rglFixupMapping(strip, tile,814ds[0], dt[0], ss[0], st[0], dsm[0], dtm[0],815(strip.flags & RGL_STRIP_TEX2) && tile.tex == tile2.tex);816if (strip.flags & RGL_STRIP_TEX2) {817glActiveTextureARB(GL_TEXTURE2_ARB);818rglFixupMapping(strip, tile2,819ds[1], dt[1], ss[1], st[1], dsm[1], dtm[1],820(strip.flags & RGL_STRIP_TEX1) && tile.tex == tile2.tex);821glActiveTextureARB(GL_TEXTURE0_ARB);822}823824glBegin(GL_TRIANGLE_STRIP);825for (k=0; k<strip.nbVtxs; k++) {826if (strip.flags & RGL_STRIP_SHADE)827glColor4ub(strip.vtxs[k].r, strip.vtxs[k].g, strip.vtxs[k].b,828strip.vtxs[k].a);829if (strip.flags & RGL_STRIP_TEX1)830glMultiTexCoord2fARB(GL_TEXTURE0_ARB,8311-(strip.vtxs[k].s + ds[0] + dsm[0]) / ss[0],8321-(strip.vtxs[k].t + dt[0] + dtm[0]) / st[0]);833if (strip.flags & RGL_STRIP_TEX2)834glMultiTexCoord2fARB(GL_TEXTURE2_ARB,8351-(strip.vtxs[k].s + ds[1] + dsm[1]) / ss[1],8361-(strip.vtxs[k].t + dt[1] + dtm[1]) / st[1]);837#ifdef RGL_EXACT_BLEND838// glMultiTexCoord2fARB(GL_TEXTURE1_ARB,839// (strip.vtxs[k].x/(buffer.width))/**strip.vtxs[k].w*/,840// (strip.vtxs[k].y/(buffer.height))/**strip.vtxs[k].w*/);841// used only to pass the viewport information :/842// tried with light position --> but it seems less precise !843glMultiTexCoord2fARB(GL_TEXTURE1_ARB,844buffer.realWidth/2048.f,845buffer.realHeight/2048.f);846#endif847// if (ds || dt || ss!=1 || st!=1) {848// printf("%g x %g --> %g x %g\n",849// strip.vtxs[k].s*tile.w,850// strip.vtxs[k].t*tile.h,851// (strip.vtxs[k].s + ds) * ss,852// (strip.vtxs[k].t + dt) * st);853// }854855float856x = strip.vtxs[k].x*strip.vtxs[k].w,857y = strip.vtxs[k].y*strip.vtxs[k].w;858859if (buffer.flags & RGL_RB_DEPTH)860glVertex3f((strip.vtxs[k].x/(buffer.width)),861(strip.vtxs[k].y/(buffer.height)),862//rglZscale(chunk.rdpState.fillColor&0xffff));863float(chunk.rdpState.fillColor&0xffff)/0xffff);864// glVertex4f((strip.vtxs[k].x/(buffer.width))*strip.vtxs[k].w,865// (strip.vtxs[k].y/(buffer.height))*strip.vtxs[k].w,866// float(chunk.rdpState.fillColor&0xffff)/0xffff*strip.vtxs[k].w,867// strip.vtxs[k].w);868else {869// glVertex4f(x/buffer.width, y/buffer.height,870// (strip.vtxs[k].z - 1.5f*zb)*(strip.vtxs[k].w),871// strip.vtxs[k].w);872873float iw = strip.vtxs[k].w;874if (iw > 1000) {875glVertex4f(x/buffer.width, y/buffer.height,876(strip.vtxs[k].z - 1.5f*zb)*strip.vtxs[k].w,877strip.vtxs[k].w);878} else {879iw = 1.0f/iw;880glVertex4f(x/buffer.width, y/buffer.height,881(strip.vtxs[k].z) / (iw + zb*0.35f),882strip.vtxs[k].w);883}884// glVertex4f(x/buffer.width, y/buffer.height,885// (strip.vtxs[k].z)*strip.vtxs[k].w,886// strip.vtxs[k].w);887}888889if (x < chunk.rdpState.clip.xh/4)890x = chunk.rdpState.clip.xh/4;891if (x > chunk.rdpState.clip.xl/4)892x = chunk.rdpState.clip.xl/4;893if (y < chunk.rdpState.clip.yh/4)894y = chunk.rdpState.clip.yh/4;895if (y > chunk.rdpState.clip.yl/4)896y = chunk.rdpState.clip.yl/4;897if (buffer.mod.xh > x)898buffer.mod.xh = x;899if (buffer.mod.xl < x)900buffer.mod.xl = x;901if (buffer.mod.yh > y)902buffer.mod.yh = y;903if (buffer.mod.yl < y)904buffer.mod.yl = y;905906}907glEnd();908909// FIXME910// glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);911912}913914buffer.flags |= RGL_RB_FBMOD;915916#ifdef RGL_EXACT_BLEND917glActiveTextureARB(GL_TEXTURE1_ARB);918glDisable(GL_TEXTURE_2D);919glBindTexture(GL_TEXTURE_2D, 0);920glActiveTextureARB(GL_TEXTURE0_ARB);921#endif922}923924glActiveTextureARB(GL_TEXTURE2_ARB);925glDisable(GL_TEXTURE_2D);926glBindTexture(GL_TEXTURE_2D, 0);927glActiveTextureARB(GL_TEXTURE0_ARB);928929renderedChunks = i;930}931932void rglDisplayFramebuffers()933{934if (!(vi_control & 3))935return;936937#ifdef RDP_DEBUG938extern int nbFullSync;939LOG("nbFyllSync %d\n", nbFullSync);940nbFullSync = 0;941#endif942943int height = (vi_control & 0x40) ? 480 : 240;944int width = vi_width;945946// from glide64947DWORD scale_x = *gfx.VI_X_SCALE_REG & 0xFFF;948if (!scale_x) return;949DWORD scale_y = *gfx.VI_Y_SCALE_REG & 0xFFF;950if (!scale_y) return;951952float fscale_x = (float)scale_x / 1024.0f;953float fscale_y = (float)scale_y / 1024.0f;954955DWORD dwHStartReg = *gfx.VI_H_START_REG;956DWORD dwVStartReg = *gfx.VI_V_START_REG;957958DWORD hstart = dwHStartReg >> 16;959DWORD hend = dwHStartReg & 0xFFFF;960961// dunno... but sometimes this happens962if (hend == hstart) {963LOG("fix hend\n");964hend = (int)(*gfx.VI_WIDTH_REG / fscale_x);965}966967if (hstart > hend) {968DWORD tmp=hstart; hstart=hend; hend=tmp;969LOG("swap hstart hend\n");970}971972DWORD vstart = dwVStartReg >> 16;973DWORD vend = dwVStartReg & 0xFFFF;974975if (vstart > vend) {976DWORD tmp=vstart; vstart=vend; vend=tmp;977LOG("swap vstart vend\n");978}979980//if (*gfx.VI_WIDTH_REG != 0x500)981if (*gfx.VI_WIDTH_REG < 0x400)982fscale_y /= 2.0f;983984// fscale_x *= screen_width / float(vi_width);985// fscale_y *= screen_height / height;986//glViewport(0*hstart*fscale_x, 0*vstart*fscale_y, (hend-hstart)*fscale_x, (vend-vstart)*fscale_y);987width = (hend-hstart)*fscale_x;988height = (vend-vstart)*fscale_y;989if (!width || !height) return;990static int oldw, oldh;991if (width == oldw && width > 200)992rglScreenWidth = width;993if (height == oldh && height > 200)994rglScreenHeight = height;995oldw = width;996oldh = height;997int vi_line = vi_width * 2; // TODO take in account the format998int vi_start = *gfx.VI_ORIGIN_REG;// - vi_line;999int vi_stop = vi_start + height * vi_line;100010011002if (*gfx.VI_WIDTH_REG >= 0x400)1003vi_line /= 2;10041005DUMP("%x screen %x --> %x %d --> %d x %d --> %d scale %g x %g clip %g --> %g x %g --> %g %dx%d\n",1006vi_line,1007vi_start, vi_stop,1008hstart, hend, vstart, vend,1009fscale_x, fscale_y,1010hstart*fscale_x, hend*fscale_x, vstart*fscale_y, vend*fscale_y,1011width, height1012);101310141015#ifdef NOFBO1016return;1017#endif10181019glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);1020glDrawBuffer(GL_BACK);1021glViewport(0, viewportOffset, screen_width, screen_height);1022glDisable(GL_SCISSOR_TEST);1023// wine seems to catch scissor test disabling so need to define an area nevertheless1024glScissor(0, viewportOffset, screen_width, screen_height);1025glClearColor(0, 0, 0, 0);1026glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);1027glClear(GL_COLOR_BUFFER_BIT); // TODO clear a minimal area10281029rglRenderBuffer_t * buffer;1030CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link)1031if (!(buffer->flags & RGL_RB_ERASED) &&1032(uint32_t)vi_stop > buffer->addressStart &&1033(uint32_t)vi_start < buffer->addressStop) {10341035if (buffer->size != 2 || buffer->format != RDP_FORMAT_RGBA)1036continue; // FIXME10371038glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);1039glDrawBuffer(GL_BACK);1040glViewport(0, viewportOffset, screen_width, screen_height);10411042glDisable(GL_SCISSOR_TEST);1043// wine seems to catch scissor test disabling so need to define an area nevertheless1044glScissor(0, viewportOffset, screen_width, screen_height);10451046glDisable(GL_ALPHA_TEST);1047glDisable(GL_BLEND);1048glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);1049glActiveTextureARB(GL_TEXTURE1_ARB);1050glDisable(GL_TEXTURE_2D);1051glActiveTextureARB(GL_TEXTURE0_ARB);1052105310541055float x = (int32_t(buffer->addressStart - vi_start) % int(vi_line)) / 2;1056float y = height - buffer->height - (int32_t(buffer->addressStart - vi_start) / int(vi_line));1057//x=y=0;1058DUMP("displaying fb %x %d x %d (%d x %d) at %g x %g\n", buffer->addressStart,1059buffer->width, buffer->height,1060buffer->realWidth, buffer->realHeight,1061x, y);1062y -= *gfx.VI_V_CURRENT_LINE_REG & 1; // prevent interlaced modes flickering1063x = x / width;1064y = y / height;1065rglUseShader(rglCopyShader);1066glBindTexture(GL_TEXTURE_2D, buffer->texid);1067glEnable(GL_TEXTURE_2D);1068glDisable(GL_DEPTH_TEST);1069glDisable(GL_BLEND);1070glColor4ub(255, 255, 255, 255);1071glBegin(GL_TRIANGLE_STRIP);1072glTexCoord2f(float(buffer->realWidth)/buffer->fboWidth, float(buffer->realHeight)/buffer->fboHeight); glVertex2f(x+float(buffer->width-1)/(width-1), y+0);1073glTexCoord2f(0, float(buffer->realHeight)/buffer->fboHeight); glVertex2f(x+0, y+0);1074glTexCoord2f(float(buffer->realWidth)/buffer->fboWidth, 0); glVertex2f(x+float(buffer->width-1)/(width-1), y+float(buffer->height-1)/(height-1));1075glTexCoord2f(0, 0); glVertex2f(x+0, y+float(buffer->height-1)/(height-1));1076glEnd();1077}1078}10791080void rglUpdate()1081{1082int i;10831084if (old_vi_origin == vi_origin) {1085//printf("same\n");1086return;1087}1088old_vi_origin = vi_origin;10891090DUMP("updating vi_origin %x vi_hstart %d vi_vstart %d\n",1091vi_origin, *gfx.VI_H_START_REG, *gfx.VI_V_START_REG);10921093glPolygonMode(GL_FRONT_AND_BACK, wireframe? GL_LINE : GL_FILL);10941095rglRenderChunks(nbChunks);10961097rglDisplayFramebuffers();10981099#ifndef NOFBO1100glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);1101#endif1102rglUseShader(0);1103glDrawBuffer(GL_BACK);1104rglSwapBuffers();11051106rglFrameCounter++;11071108// for (i=0; i<nbRBuffers; i++)1109// rglFramebuffer2Rdram(rBuffers[i],1110// rBuffers[i].addressStart, rBuffers[i].addressStop);111111121113#ifdef RDP_DEBUG1114if (rdp_dump) {1115LOG("DUMP %d\n", rdp_dump);1116rdp_dump--;1117}1118#ifdef WIN321119if (GetAsyncKeyState ('P') & 0x0001) {1120rglDebugger();1121}1122if (GetAsyncKeyState ('D') & 0x0001) {1123rdp_dump = 2;1124}1125if (GetAsyncKeyState ('W') & 0x0001) {1126wireframe = !wireframe;1127}1128#else1129SDL_Event event;1130while (nbChunks && SDL_PollEvent(&event)) {1131switch (event.type) {1132case SDL_KEYDOWN:1133switch (event.key.keysym.sym) {1134case 'd':1135rdp_dump = 2;1136break;1137case 'w': {1138wireframe = !wireframe;1139break;1140}1141case 'p': {1142rglDebugger();1143break;1144}1145}1146break;1147}1148}1149#endif1150#endif11511152#ifdef RDP_DEBUG1153rdpTracePos = 0;1154#endif11551156renderedChunks = 0;1157nbChunks = 0;1158nbStrips = 0;1159nbVtxs = 0;11601161for (i=0; i<nbRBuffers; i++) {1162rglRenderBuffer_t & buffer = rBuffers[i];1163buffer.area.xl = buffer.area.yl = 0;1164buffer.area.xh = buffer.area.yh = 8192;1165buffer.chunkId = 0;1166buffer.nbDepthSections = 0;1167}11681169// force a render buffer update1170rdpChanged |= (RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS);1171}11721173void rglClearRenderBuffers()1174{1175int i;1176for (i=0; i<nbRBuffers; i++)1177rglDeleteRenderBuffer(rBuffers[i]);1178for (i=0; i<nbZBuffers; i++) {1179glDeleteRenderbuffersEXT(1, &zBuffers[i].zbid);1180zBuffers[i].zbid = 0;1181}11821183for (i=0; i<MAX_RENDER_BUFFERS; i++) {1184rglRenderBuffer_t & buffer = rBuffers[i];1185buffer.mod.xl = buffer.mod.yl = 0;1186buffer.mod.xh = buffer.mod.yh = 8192;1187buffer.area.xl = buffer.area.yl = 0;1188buffer.area.xh = buffer.area.yh = 8192;1189}11901191CIRCLEQ_INIT(rglRenderBuffer_t, &rBufferHead);11921193nbRBuffers = 0;1194nbZBuffers = 0;1195curRBuffer = 0;1196curZBuffer = 0;1197}11981199rglRenderBuffer_t * rglSelectRenderBuffer(uint32_t addr, int width, int size, int format)1200{1201int i;1202for (i=nbRBuffers-1; i>=0; i--)1203if (rBuffers[i].addressStart == addr &&1204rBuffers[i].fbWidth == width &&1205rBuffers[i].size == size)1206break;12071208if (i >= 0) {1209return rBuffers + i;1210// TODO need to take care of framebuffer format possible change (?)1211}12121213rglAssert(nbRBuffers < MAX_RENDER_BUFFERS);1214// if (nbRBuffers == MAX_RENDER_BUFFERS)1215// rglClearRenderBuffers();12161217i = nbRBuffers++;1218rglRenderBuffer_t * cur = rBuffers + i;12191220cur->addressStart = addr;1221cur->format = format;1222cur->size = size;1223cur->fbWidth = width;1224cur->area = rdpState.clip;1225cur->line = (width << size >> 1);1226cur->flags = 0;1227CIRCLEQ_INSERT_HEAD(rglRenderBuffer_t, &rBufferHead, cur, link);1228return cur;1229}12301231void rglPrepareRendering(int texturing, int tilenum, int recth, int depth)1232{1233if (!rdpChanged)1234goto ok;12351236//rglUpdate();12371238depth = /*depth && */(RDP_GETOM_CYCLE_TYPE(rdpState.otherModes) < 2) &&1239(RDP_GETOM_Z_UPDATE_EN(rdpState.otherModes) ||1240RDP_GETOM_Z_COMPARE_EN(rdpState.otherModes));12411242if (curRBuffer)1243curRBuffer->chunkId = nbChunks;12441245if (!curZBuffer ||1246(rdpChanged & (RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS)) ||1247curZBuffer->addressStart != rdpZbAddress) {1248// first search the most recent without considering the width of the buffer1249rglRenderBuffer_t * buf;1250curZBuffer = 0;1251CIRCLEQ_FOREACH(rglRenderBuffer_t, buf, &rBufferHead, link)1252if (buf->addressStart == rdpZbAddress) {1253curZBuffer = buf;1254break;1255}1256if (!curZBuffer) {1257curZBuffer = rglSelectRenderBuffer(rdpZbAddress, rdpFbWidth, 2, RDP_FORMAT_RGBA);1258CIRCLEQ_REMOVE(&rBufferHead, curZBuffer, link);1259CIRCLEQ_INSERT_HEAD(rglRenderBuffer_t, &rBufferHead, curZBuffer, link);1260}1261}12621263if (rdpChanged & (RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS)) {1264curRBuffer = rglSelectRenderBuffer(rdpFbAddress, rdpFbWidth, rdpFbSize, rdpFbFormat);1265CIRCLEQ_REMOVE(&rBufferHead, curRBuffer, link);1266CIRCLEQ_INSERT_HEAD(rglRenderBuffer_t, &rBufferHead, curRBuffer, link);1267}12681269if (rdpChanged & (RDP_BITS_TMEM | RDP_BITS_TLUT | RDP_BITS_TILE_SETTINGS))1270rglTouchTMEM();12711272if (rdpChanged & (RDP_BITS_CLIP | RDP_BITS_ZB_SETTINGS | RDP_BITS_FB_SETTINGS) &&1273rdpState.clip.xh <= rdpState.clip.xl && rdpState.clip.yh <= rdpState.clip.yl)1274{1275if (curRBuffer->area.xh == 8192)1276curRBuffer->flags &= ~RGL_RB_HASTRIANGLES;12771278if (curRBuffer->area.xh > rdpState.clip.xh)1279curRBuffer->area.xh = rdpState.clip.xh;1280if (curRBuffer->area.xl < rdpState.clip.xl)1281curRBuffer->area.xl = rdpState.clip.xl;1282if (curRBuffer->area.yh > rdpState.clip.yh)1283curRBuffer->area.yh = rdpState.clip.yh;1284if (curRBuffer->area.yl < rdpState.clip.yl)1285curRBuffer->area.yl = rdpState.clip.yl;1286}12871288curRBuffer->chunkId = nbChunks; // don't include THIS chunk yet in case of feedback rendering (cf CBFD)1289// if (curZBuffer)1290// curZBuffer->chunkId = nbChunks;12911292curChunk = chunks + nbChunks++;1293rglAssert(nbChunks < MAX_RENDER_CHUNKS);12941295curChunk->strips = strips + nbStrips;1296curChunk->nbStrips = 0;1297curChunk->renderBuffer = curRBuffer;1298curChunk->flags = 0;1299curChunk->rdpState = rdpState;1300curChunk->depthAddress = rdpZbAddress;13011302#ifdef RDP_DEBUG1303curChunk->tracePos = rdpTracePos;1304#endif13051306if (depth) {1307curZBuffer->flags |= RGL_RB_DEPTH;1308//rglRenderChunks(curZBuffer);13091310if (rdpFbAddress != rdpZbAddress) {1311if (!curZBuffer->nbDepthSections ||1312curZBuffer->depthSections[curZBuffer->nbDepthSections-1].buffer != curRBuffer) {1313rglAssert(curZBuffer->nbDepthSections < RGL_MAX_DEPTH_SECTIONS);1314curZBuffer->depthSections[curZBuffer->nbDepthSections].buffer = curRBuffer;1315curZBuffer->nbDepthSections++;1316}1317curZBuffer->depthSections[curZBuffer->nbDepthSections-1].chunkId = nbChunks;1318}1319}13201321{1322// eliminate useless bits1323int cycle = RDP_GETOM_CYCLE_TYPE(curChunk->rdpState.otherModes);1324curChunk->rdpState.otherModes.w2 &= rdpBlendMasks[cycle].w2;1325curChunk->rdpState.combineModes.w1 &= rdpCombineMasks[cycle].w1;1326curChunk->rdpState.combineModes.w2 &= rdpCombineMasks[cycle].w2;1327}13281329rdpChanged = 0;13301331ok:1332if (texturing && !(curChunk->flags & (1<<tilenum))) {1333curChunk->flags |= (1<<tilenum);1334rglTile(rdpTiles[tilenum], curChunk->tiles[tilenum], recth);1335}1336}133713381339void rglClose()1340{13411342#ifdef RDP_DEBUG1343rglCloseDebugger();1344#endif13451346rglClearRenderBuffers();13471348rglResetTextureCache();13491350nbChunks = 0;1351nbStrips = 0;1352nbVtxs = 0;13531354if (rglCopyShader) rglDeleteShader(rglCopyShader);1355rglCopyShader = 0;1356if (rglCopyDepthShader) rglDeleteShader(rglCopyDepthShader);1357rglCopyDepthShader = 0;1358rglClearCombiners();1359}136013611362int rglInit()1363{1364static int init;1365if (!init) {1366init = 1;1367glewInit();1368}13691370glViewport(0, 0, screen_width, screen_height);13711372glLoadIdentity();1373#ifdef NOFBO1374glScalef(2, -2, 1);1375#else1376glScalef(2, 2, 1);1377#endif1378glTranslatef(-0.5, -0.5, 0);13791380glEnable(GL_DEPTH_TEST);13811382rglClose();13831384rglCopyShader = rglCreateShader(1385"void main() \n"1386"{ \n"1387" gl_Position = ftransform(); \n"1388" gl_FrontColor = gl_Color; \n"1389" gl_TexCoord[0] = gl_MultiTexCoord0; \n"1390"} \n"1391,1392"uniform sampler2D texture0; \n"1393" \n"1394"void main() \n"1395"{ \n"1396" gl_FragColor = gl_Color * texture2D(texture0, vec2(gl_TexCoord[0])); \n"1397"} \n"1398);13991400rglCopyDepthShader = rglCreateShader(1401"void main() \n"1402"{ \n"1403" gl_Position = ftransform(); \n"1404" gl_FrontColor = gl_Color; \n"1405" gl_TexCoord[0] = gl_MultiTexCoord0; \n"1406"} \n"1407,1408"uniform sampler2D texture0; \n"1409" \n"1410"void main() \n"1411"{ \n"1412" gl_FragDepth = texture2D(texture0, vec2(gl_TexCoord[0]))[0]; \n"1413"} \n"1414);14151416rdpChanged = ~0;1417return 1;1418}141914201421#ifdef __cplusplus1422extern "C" {1423#endif14241425EXPORT void CALL FBWrite(DWORD addr, DWORD size)1426{1427if (!rglSettings.fbInfo || rglSettings.async)1428return;1429//LOG("FBWrite %x\n", addr);1430rglRenderBuffer_t * buffer;1431addr &= 0x7fffff;1432CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) {1433if (addr >= buffer->addressStart && addr+size <= buffer->addressStop) {1434//LOG("FBWrite in fb #%d\n", buffer - rBuffers);1435buffer->flags &= ~RGL_RB_FBMOD;1436buffer->mod.xl = buffer->mod.yl = 0;1437buffer->mod.xh = buffer->mod.yh = 8192;1438//break;1439}1440}1441//LOG("FBWrite %x %d\n", addr, size);1442}14431444//EXPORT void CALL FBWList(FrameBufferModifyEntry *plist, DWORD size)1445//{1446// LOG("FBWList size %d\n", size);1447//}14481449EXPORT void CALL FBRead(DWORD addr)1450{1451if (!rglSettings.fbInfo || rglSettings.async)1452return;1453//LOG("FBRead %x\n", addr);1454rglRenderBuffer_t * buffer;1455addr &= 0x7fffff;1456CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) {1457if (addr >= buffer->addressStart && addr < buffer->addressStop) {1458// LOG("writing to rdram buffer %x --> %x\n",1459// buffer->addressStart, buffer->addressStop);1460rglFramebuffer2Rdram(*buffer, buffer->addressStart, buffer->addressStop);1461break;1462}1463}1464}14651466EXPORT void CALL FBGetFrameBufferInfo(void *p)1467{1468typedef struct1469{1470DWORD addr;1471DWORD size;1472DWORD width;1473DWORD height;1474} FrameBufferInfo;14751476FrameBufferInfo * pinfo = (FrameBufferInfo *)p;1477int i;14781479if (!rglSettings.fbInfo)1480return;1481//LOG("GetFbInfo\n");14821483rglRenderBuffer_t * buffer;1484i=0;1485CIRCLEQ_FOREACH(rglRenderBuffer_t, buffer, &rBufferHead, link) {1486// printf("#%d (%dx%d) %x --> %x\n", i,1487// buffer->width, buffer->height,1488// buffer->addressStart,1489// buffer->addressStart + buffer->width*buffer->height*2);1490pinfo[i].addr = buffer->addressStart;1491pinfo[i].size = 2; // FIXME1492pinfo[i].width = buffer->width;1493pinfo[i].height = buffer->height;1494i++; if (i>=6) break;1495}1496for ( ; i<6; i++) {1497pinfo[i].addr = 0;1498pinfo[i].size = 0;1499pinfo[i].width = 4;1500pinfo[i].height = 4;1501}1502}150315041505#ifdef __cplusplus1506}1507#endif15081509static char exptable[256];15101511static void build_exptable()1512{1513LOG("Building depth exp table\n");1514int i;1515for (i=0; i<256; i++) {1516int s;1517for (s=0; s<7; s++)1518if (!(i&(1<<(6-s))))1519break;1520exptable[i] = s;1521}1522}15231524void rglFramebuffer2Rdram(rglRenderBuffer_t & buffer, uint32_t start, uint32_t stop)1525{1526int depth;15271528rglRenderChunks(&buffer);15291530if (!(buffer.flags & RGL_RB_FBMOD))1531return;15321533// if (buffer.area.xh == 8192)1534// return;1535// rglAssert (buffer.area.xh != 8192);15361537depth = buffer.flags & RGL_RB_DEPTH;1538//depth = 1;15391540int glfmt, packed;1541int x, y;1542int rw, rh;1543int rx, ry;1544uint8_t * ram = gfx.RDRAM + buffer.addressStart;1545static uint8_t * fb = rglTmpTex;1546if (depth) {1547glfmt = GL_DEPTH_COMPONENT;1548//packed = GL_UNSIGNED_SHORT;1549packed = GL_FLOAT;1550} else {1551glfmt = GL_RGBA;1552packed = GL_UNSIGNED_BYTE;1553}15541555rx = buffer.mod.xh;1556ry = buffer.mod.yh;1557rw = (int(buffer.mod.xl) - int(buffer.mod.xh));1558rh = (int(buffer.mod.yl) - int(buffer.mod.yh));15591560if (rw > buffer.fbWidth)1561rw = buffer.fbWidth;15621563LOG("writing to rdram %x %s-%d %d %dx%d %dx%d %dx%d\n",1564buffer.addressStart, depth? "depth":rdpImageFormats[buffer.format], buffer.size,1565buffer.fbWidth,1566buffer.width, buffer.height,1567rx, ry,1568rw, rh);1569fflush(stderr);15701571if (rw <= 0 || rh <= 0)1572return;15731574// rx=ry=0;1575// rw = buffer.width;1576// rh = buffer.height;15771578glPushAttrib(GL_ALL_ATTRIB_BITS);1579#ifndef NOFBO1580glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);1581#endif1582glDrawBuffer(GL_BACK);1583glReadBuffer(GL_BACK);1584glDisable(GL_SCISSOR_TEST);1585glViewport(0, 0, buffer.width, buffer.height); // FIXME why +1 ?1586// wine seems to catch scissor test disabling so need to define an area nevertheless1587glScissor(0, 0, buffer.width+1, buffer.height+1);1588glEnable(GL_TEXTURE_2D);1589glDisable( GL_ALPHA_TEST );1590if (depth) {1591glBindTexture(GL_TEXTURE_2D, buffer.depthBuffer->zbid);1592rglUseShader(rglCopyDepthShader);1593glEnable(GL_DEPTH_TEST);1594glDepthFunc(GL_ALWAYS);1595glDepthMask(GL_TRUE);1596glDisable( GL_POLYGON_OFFSET_FILL );1597} else {1598glBindTexture(GL_TEXTURE_2D, buffer.texid);1599rglUseShader(rglCopyShader);1600glDisable(GL_DEPTH_TEST);1601glDisable(GL_BLEND);1602glColor4ub(255, 255, 255, 255);1603}1604glBegin(GL_TRIANGLE_STRIP);1605glTexCoord2f(1, 1); glVertex2f(1, 1);1606glTexCoord2f(0, 1); glVertex2f(0, 1);1607glTexCoord2f(1, 0); glVertex2f(1, 0);1608glTexCoord2f(0, 0); glVertex2f(0, 0);1609glEnd();16101611glReadPixels(rx, ry, rw, rh,1612glfmt, packed,1613fb);161416151616if (depth) {1617if (!exptable[255])1618build_exptable();1619for (x=rx; x<rx+rw; x++)1620for (y=ry; y<ry+rh; y++) {1621uint32_t a = *(float *)&fb[(x-rx)*4 + (y-ry)*rw*4] * ((1<<18)-1);1622//uint32_t a = uint32_t(*(uint16_t *)&fb[(x-rx)*4 + (y-ry)*rw*4]) << 2;1623int e = exptable[a>>(18-8)];16241625a = ( ( (e>=6? a : (a>>(6-e))) & ((1<<11)-1) ) << 2 ) | (e<<(16-3));16261627*(uint16_t *)&ram[(x*2 + y*buffer.line) ^ 2] =1628a;1629//int(*(uint16_t *)&fb[(x-rx)*2 + (y-ry)*rw*2])-2;1630//(*(uint16_t *)&fb[(x-rx)*2 + (y-ry)*rw*2] - int(0x8000))*2;1631//(*(float *)&fb[(x-rx)*4 + (y-ry)*rw*4]-0.5)*0x1ffff;1632}1633} else {1634switch (buffer.size) {1635case 1:1636for (x=rx; x<rx+rw; x++)1637for (y=ry; y<ry+rh; y++) {1638int r = fb[(x-rx + (y-ry)*rw)*4 + 0];1639// int g = fb[(x-rx + (y-ry)*rw)*4 + 1];1640// int b = fb[(x-rx + (y-ry)*rw)*4 + 2];1641// int a = fb[(x-rx + (y-ry)*rw)*4 + 3];1642*(uint8_t *)&ram[(x + y*buffer.line) ^ 3] =1643r;1644//(r+g+b)/3; // FIXME just R ?1645}1646break;1647case 2:1648for (x=rx; x<rx+rw; x++)1649for (y=ry; y<ry+rh; y++) {1650int r = fb[(x-rx + (y-ry)*rw)*4 + 0];1651int g = fb[(x-rx + (y-ry)*rw)*4 + 1];1652int b = fb[(x-rx + (y-ry)*rw)*4 + 2];1653int a = fb[(x-rx + (y-ry)*rw)*4 + 3];1654*(uint16_t *)&ram[(x*2 + y*buffer.line) ^ 2] =1655((r&0xf8)<<8) | ((g&0xf8)<<3) | ((b&0xf8)>>2) |1656((a&0x80)>>7);1657}1658break;1659}1660}16611662buffer.mod.xl = buffer.mod.yl = 0;1663buffer.mod.xh = buffer.mod.yh = 8192;16641665//if (start <= buffer.addressStart && stop >= buffer.addressStop)1666buffer.flags &= ~RGL_RB_FBMOD;16671668glPopAttrib();1669}16701671void rglUpdateStatus()1672{1673if (rglNextStatus != rglStatus) {1674const char * status[] = { "closed", "windowed", "fullscreen" };1675LOG("Status %s --> %s\n", status[rglStatus], status[rglNextStatus]);1676rglCloseScreen();1677rglStatus = rglNextStatus;1678if (rglNextStatus != RGL_STATUS_CLOSED)1679rglOpenScreen();1680}1681}168216831684