static inline u32 SampleNearest(int level, unsigned int u, unsigned int v) { GETextureFormat texfmt = gstate.getTextureFormat(); u32 texaddr = (gstate.texaddr[level] & 0xFFFFF0) | ((gstate.texbufwidth[level] << 8) & 0x0F000000); u8* srcptr = (u8*)Memory::GetPointer(texaddr); // TODO: not sure if this is the right place to load from...? // Special rules for kernel textures (PPGe), TODO: Verify! int texbufwidth = (texaddr < PSP_GetUserMemoryBase()) ? gstate.texbufwidth[level] & 0x1FFF : gstate.texbufwidth[level] & 0x7FF; // TODO: Should probably check if textures are aligned properly... if (texfmt == GE_TFMT_4444) { srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); return DecodeRGBA4444(*(u16*)srcptr); } else if (texfmt == GE_TFMT_5551) { srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); return DecodeRGBA5551(*(u16*)srcptr); } else if (texfmt == GE_TFMT_5650) { srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); return DecodeRGB565(*(u16*)srcptr); } else if (texfmt == GE_TFMT_8888) { srcptr += GetPixelDataOffset(32, texbufwidth*8, u, v); return DecodeRGBA8888(*(u32*)srcptr); } else if (texfmt == GE_TFMT_CLUT32) { srcptr += GetPixelDataOffset(32, texbufwidth*8, u, v); u32 val = srcptr[0] + (srcptr[1] << 8) + (srcptr[2] << 16) + (srcptr[3] << 24); return LookupColor(GetClutIndex(val), level); } else if (texfmt == GE_TFMT_CLUT16) { srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); u16 val = srcptr[0] + (srcptr[1] << 8); return LookupColor(GetClutIndex(val), level); } else if (texfmt == GE_TFMT_CLUT8) { srcptr += GetPixelDataOffset(8, texbufwidth*8, u, v); u8 val = *srcptr; return LookupColor(GetClutIndex(val), level); } else if (texfmt == GE_TFMT_CLUT4) { srcptr += GetPixelDataOffset(4, texbufwidth*8, u, v); u8 val = (u & 1) ? (srcptr[0] >> 4) : (srcptr[0] & 0xF); return LookupColor(GetClutIndex(val), level); } else {
// Copies RGBA8 data from RAM to the currently bound render target. void CopyToCurrentFboFromRam(u8* data, int srcwidth, int srcheight, int dstwidth, int dstheight) { glDisable(GL_BLEND); glViewport(0, 0, dstwidth, dstheight); glScissor(0, 0, dstwidth, dstheight); 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(); } 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]; u16 *fb16 = (u16 *)fb; for (int y = 0; y < srcheight; ++y) { u32 *buf_line = &buf[y * srcwidth]; u16 *fb_line = &fb16[y * gstate.FrameBufStride()]; switch (gstate.FrameBufFormat()) { case GE_FORMAT_565: for (int x = 0; x < srcwidth; ++x) { buf_line[x] = DecodeRGB565(fb_line[x]); } break; case GE_FORMAT_5551: for (int x = 0; x < srcwidth; ++x) { buf_line[x] = DecodeRGBA5551(fb_line[x]); } break; case GE_FORMAT_4444: for (int x = 0; x < srcwidth; ++x) { buf_line[x] = DecodeRGBA4444(fb_line[x]); } break; default: ERROR_LOG_REPORT(G3D, "Software: Unexpected framebuffer format: %d", gstate.FrameBufFormat()); } } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)srcwidth, (GLsizei)srcheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); texvert_u = 1.0f; delete[] buf; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glUseProgram(program); static const GLfloat verts[4][2] = { { -1, -1}, // Left top { -1, 1}, // left bottom { 1, 1}, // right bottom { 1, -1} // right top }; const GLfloat texverts[4][2] = { {0, 1}, {0, 0}, {texvert_u, 0}, {texvert_u, 1} }; glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, 0, verts); glVertexAttribPointer(attr_tex, 2, GL_FLOAT, GL_FALSE, 0, texverts); glEnableVertexAttribArray(attr_pos); glEnableVertexAttribArray(attr_tex); glUniform1i(uni_tex, 0); glActiveTexture(GL_TEXTURE0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray(attr_pos); glDisableVertexAttribArray(attr_tex); glBindTexture(GL_TEXTURE_2D, 0); }
// Copies RGBA8 data from RAM to the currently bound render target. void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { float dstwidth = (float)PSP_CoreParameter().pixelWidth; float dstheight = (float)PSP_CoreParameter().pixelHeight; glstate.blend.disable(); glstate.viewport.set(0, 0, dstwidth, dstheight); glstate.scissorTest.disable(); glBindTexture(GL_TEXTURE_2D, temp_texture); GLfloat texvert_u; 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 = &displayBuffer.as16[y * displayStride_]; switch (displayFormat_) { case GE_FORMAT_565: for (int x = 0; x < srcwidth; ++x) { buf_line[x] = DecodeRGB565(fb_line[x]); } break; case GE_FORMAT_5551: for (int x = 0; x < srcwidth; ++x) { buf_line[x] = DecodeRGBA5551(fb_line[x]); } break; case GE_FORMAT_4444: for (int x = 0; x < srcwidth; ++x) { buf_line[x] = DecodeRGBA4444(fb_line[x]); } break; default: ERROR_LOG_REPORT(G3D, "Software: Unexpected framebuffer format: %d", displayFormat_); } } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)srcwidth, (GLsizei)srcheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); texvert_u = 1.0f; delete[] buf; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glUseProgram(program); float x, y, w, h; CenterRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight); x /= 0.5f * dstwidth; y /= 0.5f * dstheight; w /= 0.5f * dstwidth; h /= 0.5f * dstheight; float x2 = x + w; float y2 = y + h; x -= 1.0f; y -= 1.0f; x2 -= 1.0f; y2 -= 1.0f; const GLfloat verts[4][2] = { { x, y }, // Left top { x, y2}, // left bottom { x2, y2}, // right bottom { x2, y} // right top }; const GLfloat texverts[4][2] = { {0, 1}, {0, 0}, {texvert_u, 0}, {texvert_u, 1} }; glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, 0, verts); glVertexAttribPointer(attr_tex, 2, GL_FLOAT, GL_FALSE, 0, texverts); glEnableVertexAttribArray(attr_pos); glEnableVertexAttribArray(attr_tex); glUniform1i(uni_tex, 0); glActiveTexture(GL_TEXTURE0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray(attr_pos); glDisableVertexAttribArray(attr_tex); glBindTexture(GL_TEXTURE_2D, 0); }