Merge branch 'master' of https://github.com/hrydgard/ppsspp into improvedTilControls

This commit is contained in:
bollu 2013-12-16 07:16:05 +05:30
commit fc1da7c796
17 changed files with 314 additions and 144 deletions

View File

@ -406,7 +406,7 @@ void PSPSaveDialog::DisplaySaveDataInfo1()
snprintf(saveTitle, 512, "%s", param.GetFileInfo(currentSelectedSave).saveTitle);
snprintf(saveDetail, 512, "%s", param.GetFileInfo(currentSelectedSave).saveDetail);
PPGeDrawRect(180, 136, 980, 137, CalcFadedColor(0xFFFFFFFF));
PPGeDrawRect(180, 136, 480, 137, CalcFadedColor(0xFFFFFFFF));
std::string titleTxt = title;
std::string timeTxt = time;
std::string saveTitleTxt = saveTitle;

View File

@ -776,11 +776,11 @@ u32 sceAtracGetChannel(int atracID, u32 channelAddr) {
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracGetChannel(%i, %08x): no data", atracID, channelAddr);
return ATRAC_ERROR_NO_DATA;
} else {
DEBUG_LOG(ME, "sceAtracGetChannel(%i, %08x)", atracID, channelAddr);
if (Memory::IsValidAddress(channelAddr))
Memory::Write_U32(atrac->atracChannels, channelAddr);
}
DEBUG_LOG(ME, "sceAtracGetChannel(%i, %08x)", atracID, channelAddr);
if (Memory::IsValidAddress(channelAddr))
Memory::Write_U32(atrac->atracChannels, channelAddr);
return 0;
}
@ -831,12 +831,12 @@ u32 sceAtracGetMaxSample(int atracID, u32 maxSamplesAddr) {
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracGetMaxSample(%i, %08x): no data", atracID, maxSamplesAddr);
return ATRAC_ERROR_NO_DATA;
}
DEBUG_LOG(ME, "sceAtracGetMaxSample(%i, %08x)", atracID, maxSamplesAddr);
if (Memory::IsValidAddress(maxSamplesAddr)) {
int atracSamplesPerFrame = (atrac->codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
Memory::Write_U32(atracSamplesPerFrame, maxSamplesAddr);
} else {
DEBUG_LOG(ME, "sceAtracGetMaxSample(%i, %08x)", atracID, maxSamplesAddr);
if (Memory::IsValidAddress(maxSamplesAddr)) {
int atracSamplesPerFrame = (atrac->codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
Memory::Write_U32(atracSamplesPerFrame, maxSamplesAddr);
}
}
return 0;
}
@ -849,13 +849,17 @@ u32 sceAtracGetNextDecodePosition(int atracID, u32 outposAddr) {
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracGetNextDecodePosition(%i, %08x): no data", atracID, outposAddr);
return ATRAC_ERROR_NO_DATA;
} else {
DEBUG_LOG(ME, "sceAtracGetNextDecodePosition(%i, %08x)", atracID, outposAddr);
if (atrac->currentSample >= atrac->endSample) {
if (Memory::IsValidAddress(outposAddr))
Memory::Write_U32(0, outposAddr);
return ATRAC_ERROR_ALL_DATA_DECODED;
} else {
if (Memory::IsValidAddress(outposAddr))
Memory::Write_U32(atrac->currentSample, outposAddr);
}
}
DEBUG_LOG(ME, "sceAtracGetNextDecodePosition(%i, %08x)", atracID, outposAddr);
if (atrac->currentSample >= atrac->endSample)
return ATRAC_ERROR_ALL_DATA_DECODED;
if (Memory::IsValidAddress(outposAddr))
Memory::Write_U32(atrac->currentSample, outposAddr);
return 0;
}
@ -872,6 +876,7 @@ u32 sceAtracGetNextSample(int atracID, u32 outNAddr) {
if (atrac->currentSample >= atrac->endSample) {
if (Memory::IsValidAddress(outNAddr))
Memory::Write_U32(0, outNAddr);
return ATRAC_ERROR_ALL_DATA_DECODED;
} else {
u32 numSamples = atrac->endSample - atrac->currentSample;
u32 atracSamplesPerFrame = (atrac->codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
@ -892,11 +897,11 @@ u32 sceAtracGetRemainFrame(int atracID, u32 remainAddr) {
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracGetRemainFrame(%i, %08x): no data", atracID, remainAddr);
return ATRAC_ERROR_NO_DATA;
} else {
DEBUG_LOG(ME, "sceAtracGetRemainFrame(%i, %08x)", atracID, remainAddr);
if (Memory::IsValidAddress(remainAddr))
Memory::Write_U32(atrac->getRemainFrames(), remainAddr);
}
DEBUG_LOG(ME, "sceAtracGetRemainFrame(%i, %08x)", atracID, remainAddr);
if (Memory::IsValidAddress(remainAddr))
Memory::Write_U32(atrac->getRemainFrames(), remainAddr);
return 0;
}
@ -908,12 +913,13 @@ u32 sceAtracGetSecondBufferInfo(int atracID, u32 outposAddr, u32 outBytesAddr) {
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracGetSecondBufferInfo(%i, %08x, %08x): no data", atracID, outposAddr, outBytesAddr);
return ATRAC_ERROR_NO_DATA;
} else {
ERROR_LOG(ME, "sceAtracGetSecondBufferInfo(%i, %08x, %08x)", atracID, outposAddr, outBytesAddr);
if (Memory::IsValidAddress(outposAddr) && atrac)
Memory::Write_U32(atrac->second.fileoffset, outposAddr);
if (Memory::IsValidAddress(outBytesAddr) && atrac)
Memory::Write_U32(atrac->second.writableBytes, outBytesAddr);
}
ERROR_LOG(ME, "sceAtracGetSecondBufferInfo(%i, %08x, %08x)", atracID, outposAddr, outBytesAddr);
if (Memory::IsValidAddress(outposAddr) && atrac)
Memory::Write_U32(atrac->second.fileoffset, outposAddr);
if (Memory::IsValidAddress(outBytesAddr) && atrac)
Memory::Write_U32(atrac->second.writableBytes, outBytesAddr);
// TODO: Maybe don't write the above?
return ATRAC_ERROR_SECOND_BUFFER_NOT_NEEDED;
}
@ -926,15 +932,15 @@ u32 sceAtracGetSoundSample(int atracID, u32 outEndSampleAddr, u32 outLoopStartSa
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracGetSoundSample(%i, %08x, %08x, %08x): no data", atracID, outEndSampleAddr, outLoopStartSampleAddr, outLoopEndSampleAddr);
return ATRAC_ERROR_NO_DATA;
} else {
DEBUG_LOG(ME, "sceAtracGetSoundSample(%i, %08x, %08x, %08x)", atracID, outEndSampleAddr, outLoopStartSampleAddr, outLoopEndSampleAddr);
if (Memory::IsValidAddress(outEndSampleAddr))
Memory::Write_U32(atrac->endSample, outEndSampleAddr);
if (Memory::IsValidAddress(outLoopStartSampleAddr))
Memory::Write_U32(atrac->loopStartSample, outLoopStartSampleAddr);
if (Memory::IsValidAddress(outLoopEndSampleAddr))
Memory::Write_U32(atrac->loopEndSample, outLoopEndSampleAddr);
}
DEBUG_LOG(ME, "sceAtracGetSoundSample(%i, %08x, %08x, %08x)", atracID, outEndSampleAddr, outLoopStartSampleAddr, outLoopEndSampleAddr);
if (Memory::IsValidAddress(outEndSampleAddr))
Memory::Write_U32(atrac->endSample, outEndSampleAddr);
if (Memory::IsValidAddress(outLoopStartSampleAddr))
Memory::Write_U32(atrac->loopStartSample, outLoopStartSampleAddr);
if (Memory::IsValidAddress(outLoopEndSampleAddr))
Memory::Write_U32(atrac->loopEndSample, outLoopEndSampleAddr);
return 0;
}
@ -949,19 +955,18 @@ u32 sceAtracGetStreamDataInfo(int atracID, u32 writeAddr, u32 writableBytesAddr,
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracGetStreamDataInfo(%i, %08x, %08x, %08x): no data", atracID, writeAddr, writableBytesAddr, readOffsetAddr);
return ATRAC_ERROR_NO_DATA;
} else {
DEBUG_LOG(ME, "sceAtracGetStreamDataInfo(%i, %08x, %08x, %08x)", atracID, writeAddr, writableBytesAddr, readOffsetAddr);
// reset the temp buf for adding more stream data
atrac->first.writableBytes = std::min(atrac->first.filesize - atrac->first.size, atrac->atracBufSize);
atrac->first.offset = 0;
if (Memory::IsValidAddress(writeAddr))
Memory::Write_U32(atrac->first.addr, writeAddr);
if (Memory::IsValidAddress(writableBytesAddr))
Memory::Write_U32(atrac->first.writableBytes, writableBytesAddr);
if (Memory::IsValidAddress(readOffsetAddr))
Memory::Write_U32(atrac->first.fileoffset, readOffsetAddr);
}
DEBUG_LOG(ME, "sceAtracGetStreamDataInfo(%i, %08x, %08x, %08x)", atracID, writeAddr, writableBytesAddr, readOffsetAddr);
// reset the temp buf for adding more stream data
atrac->first.writableBytes = std::min(atrac->first.filesize - atrac->first.size, atrac->atracBufSize);
atrac->first.offset = 0;
if (Memory::IsValidAddress(writeAddr))
Memory::Write_U32(atrac->first.addr, writeAddr);
if (Memory::IsValidAddress(writableBytesAddr))
Memory::Write_U32(atrac->first.writableBytes, writableBytesAddr);
if (Memory::IsValidAddress(readOffsetAddr))
Memory::Write_U32(atrac->first.fileoffset, readOffsetAddr);
return 0;
}
@ -1315,17 +1320,17 @@ u32 sceAtracSetLoopNum(int atracID, int loopNum) {
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracSetLoopNum(%i, %i):no data", atracID, loopNum);
return ATRAC_ERROR_NO_DATA;
}
// Spammed in MHU
DEBUG_LOG(ME, "sceAtracSetLoopNum(%i, %i)", atracID, loopNum);
if (atrac->loopinfoNum == 0)
return ATRAC_ERROR_NO_LOOP_INFORMATION;
atrac->loopNum = loopNum;
if (loopNum != 0 && atrac->loopinfoNum == 0) {
// Just loop the whole audio
atrac->loopStartSample = 0;
atrac->loopEndSample = atrac->endSample;
} else {
// Spammed in MHU
DEBUG_LOG(ME, "sceAtracSetLoopNum(%i, %i)", atracID, loopNum);
if (atrac->loopinfoNum == 0)
return ATRAC_ERROR_NO_LOOP_INFORMATION;
atrac->loopNum = loopNum;
if (loopNum != 0 && atrac->loopinfoNum == 0) {
// Just loop the whole audio
atrac->loopStartSample = 0;
atrac->loopEndSample = atrac->endSample;
}
}
return 0;
}
@ -1385,11 +1390,11 @@ int sceAtracGetOutputChannel(int atracID, u32 outputChanPtr) {
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracGetOutputChannel(%i, %08x): no data", atracID, outputChanPtr);
return ATRAC_ERROR_NO_DATA;
} else {
DEBUG_LOG(ME, "sceAtracGetOutputChannel(%i, %08x)", atracID, outputChanPtr);
if (Memory::IsValidAddress(outputChanPtr))
Memory::Write_U32(atrac->atracOutputChannels, outputChanPtr);
}
DEBUG_LOG(ME, "sceAtracGetOutputChannel(%i, %08x)", atracID, outputChanPtr);
if (Memory::IsValidAddress(outputChanPtr))
Memory::Write_U32(atrac->atracOutputChannels, outputChanPtr);
return 0;
}
@ -1401,7 +1406,7 @@ int sceAtracIsSecondBufferNeeded(int atracID) {
} else if (!atrac->data_buf) {
ERROR_LOG(ME, "sceAtracIsSecondBufferNeeded(%i): no data", atracID);
return ATRAC_ERROR_NO_DATA;
}
}
WARN_LOG(ME, "UNIMPL sceAtracIsSecondBufferNeeded(%i)", atracID);
return 0;
}

View File

@ -462,7 +462,7 @@ void DoFrameTiming(bool &throttle, bool &skipFrame, float timestep) {
if (curFrameTime > nextFrameTime && doFrameSkip) {
skipFrame = true;
}
} else if (g_Config.iFrameSkip > 1) {
} else if (g_Config.iFrameSkip > 1) {
// Other values = fixed frameskip
if (numSkippedFrames >= g_Config.iFrameSkip - 1)
skipFrame = false;
@ -563,9 +563,15 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
// 1.001f to compensate for the classic 59.94 NTSC framerate that the PSP seems to have.
DoFrameTiming(throttle, skipFrame, (float)numVBlanksSinceFlip * (1.001f / 60.0f));
// Max 4 skipped frames in a row - 15 fps is really the bare minimum for playability.
// We check for 3 here so it's 3 skipped frames, 1 non skipped, 3 skipped, etc.
int maxFrameskip = throttle ? g_Config.iFrameSkip : 8;
int maxFrameskip = 8;
if (throttle) {
if (g_Config.iFrameSkip == 1) {
// 4 here means 1 drawn, 4 skipped - so 12 fps minimum.
maxFrameskip = 4;
} else {
maxFrameskip = g_Config.iFrameSkip - 1;
}
}
if (numSkippedFrames >= maxFrameskip) {
skipFrame = false;
}

View File

@ -287,7 +287,7 @@ void PPGeBegin()
PPGeSetDefaultTexture();
WriteCmd(GE_CMD_SCISSOR1, (0 << 10) | 0);
WriteCmd(GE_CMD_SCISSOR2, (1023 << 10) | 1023);
WriteCmd(GE_CMD_SCISSOR2, (271 << 10) | 479);
WriteCmd(GE_CMD_MINZ, 0);
WriteCmd(GE_CMD_MAXZ, 0xFFFF);

View File

@ -15,11 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#if defined(USING_GLES2)
#define GLSL_ES_1_0
#else
#define GLSL_1_3
#if !defined(USING_GLES2)
// SDL 1.2 on Apple does not have support for OpenGL 3 and hence needs
// special treatment in the shader generator.
#if defined(__APPLE__)
@ -131,6 +127,11 @@ bool CanReplaceAlphaWithStencil() {
if (!gstate.isStencilTestEnabled()) {
return false;
}
if (gl_extensions.ARB_blend_func_extended) {
return true;
}
if (gstate.isAlphaBlendEnabled()) {
return nonAlphaSrcFactors[gstate.getBlendFuncA()] && nonAlphaDestFactors[gstate.getBlendFuncA()];
}
@ -295,27 +296,49 @@ void ComputeFragmentShaderID(FragmentShaderID *id) {
void GenerateFragmentShader(char *buffer) {
char *p = buffer;
// In GLSL ES 3.0, you use "in" variables instead of varying.
bool glslES30 = false;
const char *varying = "varying";
bool highpFog = false;
#if defined(GLSL_ES_1_0)
WRITE(p, "#version 100\n"); // GLSL ES 1.0
#if defined(USING_GLES2)
// Let's wait until we have a real use for this.
// ES doesn't support dual source alpha :(
if (false && gl_extensions.GLES3) {
WRITE(p, "#version 300 es\n"); // GLSL ES 1.0
glslES30 = true;
} else {
WRITE(p, "#version 100\n"); // GLSL ES 1.0
}
WRITE(p, "precision lowp float;\n");
// PowerVR needs highp to do the fog in MHU correctly.
// Others don't, and some can't handle highp in the fragment shader.
highpFog = gl_extensions.gpuVendor == GPU_VENDOR_POWERVR;
#elif !defined(FORCE_OPENGL_2_0)
WRITE(p, "#version 110\n");
// Remove lowp/mediump in non-mobile implementations
WRITE(p, "#define lowp\n");
WRITE(p, "#define mediump\n");
WRITE(p, "#define highp\n");
if (gl_extensions.VersionGEThan(3, 3, 0)) {
glslES30 = true;
WRITE(p, "#version 330\n");
} else if (gl_extensions.VersionGEThan(3, 0, 0)) {
WRITE(p, "#version 130\n");
} else {
WRITE(p, "#version 110\n");
// Remove lowp/mediump in non-mobile non-glsl 3 implementations
WRITE(p, "#define lowp\n");
WRITE(p, "#define mediump\n");
WRITE(p, "#define highp\n");
}
#else
// Remove lowp/mediump in non-mobile implementations
// Need to remove lowp/mediump for Mac
WRITE(p, "#define lowp\n");
WRITE(p, "#define mediump\n");
WRITE(p, "#define highp\n");
#endif
if (glslES30) {
varying = "in";
}
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled();
bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
@ -343,19 +366,19 @@ void GenerateFragmentShader(char *buffer) {
if (gstate.isTextureMapEnabled() && gstate.getTextureFunction() == GE_TEXFUNC_BLEND)
WRITE(p, "uniform lowp vec3 u_texenv;\n");
WRITE(p, "varying lowp vec4 v_color0;\n");
WRITE(p, "%s lowp vec4 v_color0;\n", varying);
if (lmode)
WRITE(p, "varying lowp vec3 v_color1;\n");
WRITE(p, "%s lowp vec3 v_color1;\n", varying);
if (enableFog) {
WRITE(p, "uniform lowp vec3 u_fogcolor;\n");
WRITE(p, "varying %s float v_fogdepth;\n", highpFog ? "highp" : "mediump");
WRITE(p, "%s %s float v_fogdepth;\n", varying, highpFog ? "highp" : "mediump");
}
if (doTexture)
{
if (doTextureProjection)
WRITE(p, "varying mediump vec3 v_texcoord;\n");
WRITE(p, "%s mediump vec3 v_texcoord;\n", varying);
else
WRITE(p, "varying mediump vec2 v_texcoord;\n");
WRITE(p, "%s mediump vec2 v_texcoord;\n", varying);
}
if (enableAlphaTest) {
@ -370,12 +393,16 @@ void GenerateFragmentShader(char *buffer) {
else
WRITE(p, "vec3 roundAndScaleTo255v(in vec3 x) { return floor(x * 255.0 + 0.5); }\n");
}
if (gl_extensions.ARB_blend_func_extended) {
WRITE(p, "out lowp vec4 fragColor0;\n");
WRITE(p, "out lowp vec4 fragColor1;\n");
}
WRITE(p, "void main() {\n");
if (gstate.isModeClear()) {
// Clear mode does not allow any fancy shading.
WRITE(p, " gl_FragColor = v_color0;\n");
WRITE(p, " vec4 v = v_color0;\n");
} else {
const char *secondary = "";
// Secondary color for specular on top of texture
@ -475,31 +502,38 @@ void GenerateFragmentShader(char *buffer) {
if (enableFog) {
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " gl_FragColor = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
// WRITE(p, " v.x = v_depth;\n");
} else {
WRITE(p, " gl_FragColor = v;\n");
}
}
const char *fragColor = "gl_FragColor";
if (gl_extensions.ARB_blend_func_extended) {
WRITE(p, " fragColor0 = vec4(v.rgb, 0.0);\n");
WRITE(p, " fragColor1 = vec4(0.0, 0.0, 0.0, v.a);\n");
fragColor = "fragColor0";
} else {
WRITE(p, " gl_FragColor = v;\n");
}
if (stencilToAlpha) {
switch (ReplaceAlphaWithStencilType()) {
case STENCIL_VALUE_UNIFORM:
WRITE(p, " gl_FragColor.a = u_stencilReplaceValue;\n");
WRITE(p, " %s.a = u_stencilReplaceValue;\n", fragColor);
break;
case STENCIL_VALUE_ZERO:
WRITE(p, " gl_FragColor.a = 0.0;\n");
WRITE(p, " %s.a = 0.0;\n", fragColor);
break;
case STENCIL_VALUE_ONE:
WRITE(p, " gl_FragColor.a = 1.0;\n");
WRITE(p, " %s.a = 1.0;\n", fragColor);
break;
case STENCIL_VALUE_UNKNOWN:
// Maybe we should even mask away alpha using glColorMask and not change it at all? We do get here
// if the stencil mode is KEEP for example.
WRITE(p, " gl_FragColor.a = 0.0;\n");
WRITE(p, " %s.a = 0.0;\n", fragColor);
break;
case STENCIL_VALUE_KEEP:

View File

@ -570,7 +570,7 @@ static void EstimateDrawingSize(int &drawing_width, int &drawing_height) {
int region_height = gstate.getRegionY2() + 1;
int scissor_width = gstate.getScissorX2() + 1;
int scissor_height = gstate.getScissorY2() + 1;
int fb_stride = gstate.fbwidth & 0x3C0;
int fb_stride = gstate.FrameBufStride();
DEBUG_LOG(SCEGE,"viewport : %ix%i, region : %ix%i , scissor: %ix%i, stride: %i, %i", viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_stride, gstate.isModeThrough());
@ -662,10 +662,10 @@ void FramebufferManager::SetRenderFrameBuffer() {
// Get parameters
u32 fb_address = gstate.getFrameBufRawAddress();
int fb_stride = gstate.fbwidth & 0x3C0;
int fb_stride = gstate.FrameBufStride();
u32 z_address = gstate.getDepthBufRawAddress();
int z_stride = gstate.zbwidth & 0x3C0;
int z_stride = gstate.DepthBufStride();
// Yeah this is not completely right. but it'll do for now.
//int drawing_width = ((gstate.region2) & 0x3FF) + 1;
@ -1557,7 +1557,7 @@ void FramebufferManager::Resized() {
bool FramebufferManager::GetCurrentFramebuffer(GPUDebugBuffer &buffer) {
u32 fb_address = gstate.getFrameBufRawAddress();
int fb_stride = gstate.fbwidth & 0x3C0;
int fb_stride = gstate.FrameBufStride();
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
@ -1584,10 +1584,10 @@ bool FramebufferManager::GetCurrentFramebuffer(GPUDebugBuffer &buffer) {
bool FramebufferManager::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) {
u32 fb_address = gstate.getFrameBufRawAddress();
int fb_stride = gstate.fbwidth & 0x3C0;
int fb_stride = gstate.FrameBufStride();
u32 z_address = gstate.getDepthBufRawAddress();
int z_stride = gstate.zbwidth & 0x3C0;
int z_stride = gstate.DepthBufStride();
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {
@ -1617,7 +1617,7 @@ bool FramebufferManager::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) {
bool FramebufferManager::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) {
u32 fb_address = gstate.getFrameBufRawAddress();
int fb_stride = gstate.fbwidth & 0x3C0;
int fb_stride = gstate.FrameBufStride();
VirtualFramebuffer *vfb = currentRenderVfb_;
if (!vfb) {

View File

@ -1549,8 +1549,13 @@ void GLES_GPU::DoBlockTransfer() {
// TODO: Notify all overlapping FBOs that they need to reload.
textureCache_.Invalidate(dstBasePtr + (dstY * dstStride + dstX) * bpp, height * dstStride * bpp, GPU_INVALIDATE_HINT);
if (Memory::IsRAMAddress(srcBasePtr) && Memory::IsVRAMAddress(dstBasePtr))
framebufferManager_.UpdateFromMemory(dstBasePtr, (dstY + height) * dstStride * bpp, true);
if (Memory::IsRAMAddress(srcBasePtr) && Memory::IsVRAMAddress(dstBasePtr)) {
// TODO: This causes glitches in Tactics Ogre if we don't implement both ways (which will probably be slow...)
// The main thing this helps is videos, which will have a matching stride, and zero x/y.
if (dstStride == srcStride && dstY == 0 && dstX == 0 && srcX == 0 && srcY == 0) {
framebufferManager_.UpdateFromMemory(dstBasePtr, (dstY + height) * dstStride * bpp, true);
}
}
// A few games use this INSTEAD of actually drawing the video image to the screen, they just blast it to
// the backbuffer. Detect this and have the framebuffermanager draw the pixels.

View File

@ -96,6 +96,14 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTrans
glBindAttribLocation(program, ATTR_COLOR0, "color0");
glBindAttribLocation(program, ATTR_COLOR1, "color1");
#ifndef USING_GLES2
if (gl_extensions.ARB_blend_func_extended) {
// Dual source alpha
glBindFragDataLocationIndexed(program, 0, 0, "fragColor0");
glBindFragDataLocationIndexed(program, 0, 1, "fragColor1");
}
#endif
glLinkProgram(program);
// Detaching shaders is annoying when debugging with gDebugger
@ -213,6 +221,8 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs, u32 vertType, bool useHWTrans
if (u_world != -1) availableUniforms |= DIRTY_WORLDMATRIX;
if (u_view != -1) availableUniforms |= DIRTY_VIEWMATRIX;
if (u_texmtx != -1) availableUniforms |= DIRTY_TEXMATRIX;
if (u_stencilReplaceValue != -1) availableUniforms |= DIRTY_STENCILREPLACEVALUE;
// Looping up to numBones lets us avoid checking u_bone[i]
for (int i = 0; i < numBones; i++) {
if (u_bone[i] != -1)
@ -474,7 +484,7 @@ void LinkedShader::UpdateUniforms(u32 vertType) {
}
if (dirty & DIRTY_STENCILREPLACEVALUE) {
glUniform1f(u_stencilReplaceValue, gstate.getStencilTestRef());
glUniform1f(u_stencilReplaceValue, (float)gstate.getStencilTestRef() * (1.0f / 255.0f));
}
// TODO: Could even set all bones in one go if they're all dirty.
#ifdef USE_BONE_ARRAY

View File

@ -129,6 +129,19 @@ static const GLushort logicOps[] = {
};
#endif
static GLenum toDualSource(GLenum blendfunc) {
switch (blendfunc) {
#ifndef USING_GLES2
case GL_SRC_ALPHA:
return GL_SRC1_ALPHA;
case GL_ONE_MINUS_SRC_ALPHA:
return GL_ONE_MINUS_SRC1_ALPHA;
#endif
default:
return blendfunc;
}
}
static GLenum blendColor2Func(u32 fix) {
if (fix == 0xFFFFFF)
return GL_ONE;
@ -182,13 +195,19 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
float constantAlpha = 1.0f;
if (gstate.isStencilTestEnabled() && !CanReplaceAlphaWithStencil()) {
if (gstate.isStencilTestEnabled() == STENCIL_VALUE_UNIFORM) {
constantAlpha = gstate.getStencilTestRef() * (1.0f / 255.0f);
constantAlpha = (float) gstate.getStencilTestRef() * (1.0f / 255.0f);
}
}
// Shortcut by using GL_ONE where possible, no need to set blendcolor
GLuint glBlendFuncA = blendFuncA == GE_SRCBLEND_FIXA ? blendColor2Func(gstate.getFixA()) : aLookup[blendFuncA];
GLuint glBlendFuncB = blendFuncB == GE_DSTBLEND_FIXB ? blendColor2Func(gstate.getFixB()) : bLookup[blendFuncB];
if (gl_extensions.ARB_blend_func_extended) {
glBlendFuncA = toDualSource(glBlendFuncA);
glBlendFuncB = toDualSource(glBlendFuncB);
}
if (blendFuncA == GE_SRCBLEND_FIXA || blendFuncB == GE_DSTBLEND_FIXB) {
Vec3f fixA = Vec3f::FromRGB(gstate.getFixA());
Vec3f fixB = Vec3f::FromRGB(gstate.getFixB());

View File

@ -139,16 +139,37 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
// #define USE_FOR_LOOP
// In GLSL ES 3.0, you use "out" variables instead.
bool glslES30 = false;
const char *varying = "varying";
const char *attribute = "attribute";
bool highpFog = false;
#if defined(USING_GLES2)
WRITE(p, "#version 100\n"); // GLSL ES 1.0
// Let's wait until we have a real use for this.
// ES doesn't support dual source alpha :(
if (false && gl_extensions.GLES3) {
WRITE(p, "version 300 es\n");
glslES30 = true;
} else {
WRITE(p, "#version 100\n"); // GLSL ES 1.0
}
WRITE(p, "precision highp float;\n");
// PowerVR needs highp to do the fog in MHU correctly.
// Others don't, and some can't handle highp in the fragment shader.
highpFog = gl_extensions.gpuVendor == GPU_VENDOR_POWERVR;
#elif !defined(FORCE_OPENGL_2_0)
WRITE(p, "#version 110\n");
// Remove lowp/mediump in non-mobile implementations
WRITE(p, "#define lowp\n");
WRITE(p, "#define mediump\n");
WRITE(p, "#define highp\n");
if (gl_extensions.VersionGEThan(3, 3, 0)) {
glslES30 = true;
WRITE(p, "#version 330\n");
} else {
WRITE(p, "#version 110\n");
// Remove lowp/mediump in non-mobile non-glsl 3 implementations
WRITE(p, "#define lowp\n");
WRITE(p, "#define mediump\n");
WRITE(p, "#define highp\n");
}
#else
// Need to remove lowp/mediump for Mac
WRITE(p, "#define lowp\n");
@ -156,6 +177,11 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
WRITE(p, "#define highp\n");
#endif
if (glslES30) {
attribute = "in";
varying = "out";
}
int lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled();
int doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear();
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
@ -185,23 +211,23 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
}
if (useHWTransform)
WRITE(p, "attribute vec3 position;\n");
WRITE(p, "%s vec3 position;\n", attribute);
else
WRITE(p, "attribute vec4 position;\n"); // need to pass the fog coord in w
WRITE(p, "%s vec4 position;\n", attribute); // need to pass the fog coord in w
if (useHWTransform && hasNormal)
WRITE(p, "attribute mediump vec3 normal;\n");
WRITE(p, "%s mediump vec3 normal;\n", attribute);
if (doTexture) {
if (!useHWTransform && doTextureProjection)
WRITE(p, "attribute vec3 texcoord;\n");
WRITE(p, "%s vec3 texcoord;\n", attribute);
else
WRITE(p, "attribute vec2 texcoord;\n");
WRITE(p, "%s vec2 texcoord;\n", attribute);
}
if (hasColor) {
WRITE(p, "attribute lowp vec4 color0;\n");
WRITE(p, "%s lowp vec4 color0;\n", attribute);
if (lmode && !useHWTransform) // only software transform supplies color1 as vertex data
WRITE(p, "attribute lowp vec3 color1;\n");
WRITE(p, "%s lowp vec3 color1;\n", attribute);
}
if (gstate.isModeThrough()) {
@ -272,22 +298,24 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf
WRITE(p, "uniform highp vec2 u_fogcoef;\n");
}
WRITE(p, "varying lowp vec4 v_color0;\n");
if (lmode) WRITE(p, "varying lowp vec3 v_color1;\n");
WRITE(p, "%s lowp vec4 v_color0;\n", varying);
if (lmode) {
WRITE(p, "%s lowp vec3 v_color1;\n", varying);
}
if (doTexture) {
if (doTextureProjection)
WRITE(p, "varying mediump vec3 v_texcoord;\n");
WRITE(p, "%s mediump vec3 v_texcoord;\n", varying);
else
WRITE(p, "varying mediump vec2 v_texcoord;\n");
WRITE(p, "%s mediump vec2 v_texcoord;\n", varying);
}
if (enableFog) {
// See the fragment shader generator
if (gl_extensions.gpuVendor == GPU_VENDOR_POWERVR) {
WRITE(p, "varying highp float v_fogdepth;\n");
if (highpFog) {
WRITE(p, "%s highp float v_fogdepth;\n", varying);
} else {
WRITE(p, "varying mediump float v_fogdepth;\n");
WRITE(p, "%s mediump float v_fogdepth;\n", varying);
}
}

View File

@ -218,10 +218,10 @@ struct GPUgstate
// 0x44000000 is uncached VRAM.
u32 getFrameBufAddress() const { return 0x44000000 | getFrameBufRawAddress(); }
GEBufferFormat FrameBufFormat() const { return static_cast<GEBufferFormat>(framebufpixformat & 3); }
int FrameBufStride() const { return fbwidth&0x7C0; }
int FrameBufStride() const { return fbwidth&0x7FC; }
u32 getDepthBufRawAddress() const { return (zbptr & 0xFFFFFF) | ((zbwidth & 0xFF0000) << 8); }
u32 getDepthBufAddress() const { return 0x44000000 | getDepthBufRawAddress(); }
int DepthBufStride() const { return zbwidth&0x7C0; }
int DepthBufStride() const { return zbwidth&0x7FC; }
// Pixel Pipeline
bool isModeClear() const { return clearmode & 1; }

View File

@ -173,6 +173,7 @@ public:
Vec3() {}
Vec3(const T a[3]) : x(a[0]), y(a[1]), z(a[2]) {}
Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {}
Vec3(const Vec2<T>& _xy, const T& _z) : x(_xy.x), y(_xy.y), z(_z) {}
template<typename T2>
Vec3<T2> Cast() const
@ -334,6 +335,8 @@ public:
Vec4() {}
Vec4(const T a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {}
Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {}
Vec4(const Vec2<T>& _xy, const T& _z, const T& _w) : x(_xy.x), y(_xy.y), z(_z), w(_w) {}
Vec4(const Vec3<T>& _xyz, const T& _w) : x(_xyz.x), y(_xyz.y), z(_xyz.z), w(_w) {}
template<typename T2>
Vec4<T2> Cast() const

View File

@ -70,8 +70,7 @@ static inline int GetPixelDataOffset(unsigned int row_pitch_bits, unsigned int u
(tile_u % tiles_in_block_horizontal) +
(tile_u / tiles_in_block_horizontal) * (tiles_in_block_horizontal*tiles_in_block_vertical);
// TODO: HACK: for some reason, the second part needs to be diviced by two for CLUT4 textures to work properly.
return tile_idx * tile_size_bits/8 + ((u % (tile_size_bits / texel_size_bits)))/((texel_size_bits == 4) ? 2 : 1);
return tile_idx * (tile_size_bits / 8) + ((u % texels_per_tile) * texel_size_bits) / 8;
}
static inline u32 LookupColor(unsigned int index, unsigned int level)
@ -206,10 +205,18 @@ static inline void GetTextureCoordinates(const VertexData& v0, const VertexData&
{
// projection mapping, TODO: Move this code to TransformUnit!
Vec3<float> source;
if (gstate.getUVProjMode() == GE_PROJMAP_POSITION) {
switch (gstate.getUVProjMode()) {
case GE_PROJMAP_POSITION:
source = ((v0.modelpos * w0 + v1.modelpos * w1 + v2.modelpos * w2) / (w0+w1+w2));
} else {
break;
case GE_PROJMAP_UV:
source = Vec3f((v0.texturecoords * w0 + v1.texturecoords * w1 + v2.texturecoords * w2) / (w0 + w1 + w2), 0.0f);
break;
default:
ERROR_LOG_REPORT(G3D, "Software: Unsupported UV projection mode %x", gstate.getUVProjMode());
break;
}
Mat3x3<float> tgen(gstate.tgenMatrix);
@ -875,6 +882,10 @@ void DrawTriangleSlice(
w1_base += orient2dIncY(-d02.x) * 16 * y1;
w2_base += orient2dIncY(d01.x) * 16 * y1;
// All the z values are the same, no interpolation required.
// This is common, and when we interpolate, we lose accuracy.
const bool flatZ = v0.screenpos.z == v1.screenpos.z && v0.screenpos.z == v2.screenpos.z;
for (pprime.y = minY + y1 * 16; pprime.y < minY + y2 * 16; pprime.y += 16,
w0_base += orient2dIncY(d12.x)*16,
w1_base += orient2dIncY(-d02.x)*16,
@ -986,9 +997,10 @@ void DrawTriangleSlice(
Vec4<int> texcolor_tr = Vec4<int>::FromRGBA(SampleNearest(texlevel, u[1], v[1], tptr, bufwbits));
Vec4<int> texcolor_bl = Vec4<int>::FromRGBA(SampleNearest(texlevel, u[2], v[2], tptr, bufwbits));
Vec4<int> texcolor_br = Vec4<int>::FromRGBA(SampleNearest(texlevel, u[3], v[3], tptr, bufwbits));
Vec4<int> t = texcolor_tl * (0xff - frac_u) + texcolor_tr * frac_u;
Vec4<int> b = texcolor_bl * (0xff - frac_u) + texcolor_br * frac_u;
texcolor = (t * (0xff - frac_v) + b * frac_v) / (256 * 256);
// 0x100 causes a slight bias to tl, but without it we'd have to divide by 255 * 255.
Vec4<int> t = texcolor_tl * (0x100 - frac_u) + texcolor_tr * frac_u;
Vec4<int> b = texcolor_bl * (0x100 - frac_u) + texcolor_br * frac_u;
texcolor = (t * (0x100 - frac_v) + b * frac_v) / (256 * 256);
}
Vec4<int> out = GetTextureFunctionOutput(prim_color_rgb, prim_color_a, texcolor);
prim_color_rgb = out.rgb();
@ -1006,9 +1018,11 @@ void DrawTriangleSlice(
// TODO: Fogging
u16 z = v2.screenpos.z;
// TODO: Is that the correct way to interpolate?
// Without the (u32), this causes an ICE in some versions of gcc.
u16 z = (u16)(u32)(((float)v0.screenpos.z * w0 + (float)v1.screenpos.z * w1 + (float)v2.screenpos.z * w2) * wsum);
if (!flatZ)
z = (u16)(u32)(((float)v0.screenpos.z * w0 + (float)v1.screenpos.z * w1 + (float)v2.screenpos.z * w2) * wsum);
// Depth range test
// TODO: Clear mode?

View File

@ -19,6 +19,7 @@
#include "GPU/GPUState.h"
#include "GPU/ge_constants.h"
#include "GPU/Common/TextureDecoder.h"
#include "Core/Config.h"
#include "Core/Debugger/Breakpoints.h"
#include "Core/MemMap.h"
#include "Core/HLE/sceKernelInterrupt.h"
@ -145,6 +146,12 @@ SoftGPU::SoftGPU()
fb.data = Memory::GetPointer(0x44000000); // TODO: correct default address?
depthbuf.data = Memory::GetPointer(0x44000000); // TODO: correct default address?
framebufferDirty_ = true;
// TODO: Is there a default?
displayFramebuf_ = 0;
displayStride_ = 512;
displayFormat_ = GE_FORMAT_8888;
}
SoftGPU::~SoftGPU()
@ -154,7 +161,7 @@ SoftGPU::~SoftGPU()
}
// Copies RGBA8 data from RAM to the currently bound render target.
void SoftGPU::CopyToCurrentFboFromRam(u8* data, int srcwidth, int srcheight, int dstwidth, int dstheight)
void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight, int dstwidth, int dstheight)
{
glDisable(GL_BLEND);
glViewport(0, 0, dstwidth, dstheight);
@ -163,18 +170,25 @@ void SoftGPU::CopyToCurrentFboFromRam(u8* data, int srcwidth, int srcheight, int
glBindTexture(GL_TEXTURE_2D, temp_texture);
GLfloat texvert_u;
if (gstate.FrameBufFormat() == GE_FORMAT_8888) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)gstate.FrameBufStride(), (GLsizei)srcheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
texvert_u = (float)srcwidth / gstate.FrameBufStride();
if (displayFramebuf_ == 0) {
u32 data[] = {0};
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
texvert_u = 1.0f;
} else if (displayFormat_ == GE_FORMAT_8888) {
u8 *data = Memory::GetPointer(displayFramebuf_);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)displayStride_, (GLsizei)srcheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
texvert_u = (float)srcwidth / displayStride_;
} else {
// TODO: This should probably be converted in a shader instead..
// TODO: Do something less brain damaged to manage this buffer...
u32 *buf = new u32[srcwidth * srcheight];
FormatBuffer displayBuffer;
displayBuffer.data = Memory::GetPointer(displayFramebuf_);
for (int y = 0; y < srcheight; ++y) {
u32 *buf_line = &buf[y * srcwidth];
const u16 *fb_line = &fb.as16[y * gstate.FrameBufStride()];
const u16 *fb_line = &displayBuffer.as16[y * displayStride_];
switch (gstate.FrameBufFormat()) {
switch (displayFormat_) {
case GE_FORMAT_565:
for (int x = 0; x < srcwidth; ++x) {
buf_line[x] = DecodeRGB565(fb_line[x]);
@ -194,7 +208,7 @@ void SoftGPU::CopyToCurrentFboFromRam(u8* data, int srcwidth, int srcheight, int
break;
default:
ERROR_LOG_REPORT(G3D, "Software: Unexpected framebuffer format: %d", gstate.FrameBufFormat());
ERROR_LOG_REPORT(G3D, "Software: Unexpected framebuffer format: %d", displayFormat_);
}
}
@ -242,7 +256,8 @@ void SoftGPU::CopyDisplayToOutput()
void SoftGPU::CopyDisplayToOutputInternal()
{
// The display always shows 480x272.
CopyToCurrentFboFromRam(fb.data, FB_WIDTH, FB_HEIGHT, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
CopyToCurrentFboFromDisplayRam(FB_WIDTH, FB_HEIGHT, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
framebufferDirty_ = false;
}
void SoftGPU::ProcessEvent(GPUEvent ev) {
@ -354,6 +369,7 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff)
cyclesExecuted += EstimatePerVertexCost() * count;
int bytesRead;
TransformUnit::SubmitPrimitive(verts, indices, type, count, gstate.vertType, &bytesRead);
framebufferDirty_ = true;
// After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed).
// Some games rely on this, they don't bother reloading VADDR and IADDR.
@ -408,6 +424,7 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff)
if (!(gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME)) {
TransformUnit::SubmitSpline(control_points, indices, sp_ucount, sp_vcount, sp_utype, sp_vtype, gstate.getPatchPrimitiveType(), gstate.vertType);
}
framebufferDirty_ = true;
DEBUG_LOG(G3D,"DL DRAW SPLINE: %i x %i, %i x %i", sp_ucount, sp_vcount, sp_utype, sp_vtype);
}
break;
@ -570,6 +587,8 @@ void SoftGPU::ExecuteOp(u32 op, u32 diff)
CBreakPoints::ExecMemCheck(dstBasePtr + (srcY * dstStride + srcX) * bpp, true, height * dstStride * bpp, currentMIPS->pc);
#endif
// Could theoretically dirty the framebuffer.
framebufferDirty_ = true;
break;
}
@ -797,6 +816,22 @@ void SoftGPU::UpdateMemory(u32 dest, u32 src, int size)
{
// Nothing to update.
InvalidateCache(dest, size, GPU_INVALIDATE_HINT);
// Let's just be safe.
framebufferDirty_ = true;
}
bool SoftGPU::FramebufferDirty() {
if (g_Config.bSeparateCPUThread) {
// Allow it to process fully before deciding if it's dirty.
SyncThread();
}
if (g_Config.iFrameSkip != 0) {
bool dirty = framebufferDirty_;
framebufferDirty_ = false;
return dirty;
}
return true;
}
bool SoftGPU::GetCurrentFramebuffer(GPUDebugBuffer &buffer)

View File

@ -56,6 +56,9 @@ public:
virtual void BeginFrame() {}
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
displayFramebuf_ = framebuf;
displayStride_ = stride;
displayFormat_ = format;
host->GPUNotifyDisplay(framebuf, stride, format);
}
virtual void CopyDisplayToOutput();
@ -73,6 +76,8 @@ public:
fullInfo = "Software";
}
virtual bool FramebufferDirty();
virtual bool FramebufferReallyDirty() {
return !(gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME);
}
@ -85,8 +90,13 @@ public:
protected:
virtual void FastRunLoop(DisplayList &list);
virtual void ProcessEvent(GPUEvent ev);
void CopyToCurrentFboFromRam(u8* data, int srcwidth, int srcheight, int dstwidth, int dstheight);
void CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight, int dstwidth, int dstheight);
private:
void CopyDisplayToOutputInternal();
bool framebufferDirty_;
u32 displayFramebuf_;
u32 displayStride_;
GEBufferFormat displayFormat_;
};

View File

@ -676,4 +676,4 @@ void EmuScreen::autoLoad() {
if (g_Config.bEnableAutoLoad && lastSlot != -1) {
SaveState::LoadSlot(lastSlot, 0, 0);
}
};
}

View File

@ -343,6 +343,7 @@ int main(int argc, const char* argv[])
g_Config.iInternalResolution = 1;
g_Config.bFrameSkipUnthrottle = false;
g_Config.bEnableLogging = fullLog;
g_Config.iNumWorkerThreads = 1;
#ifdef _WIN32
InitSysDirectories();