// 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; T3DViewport viewport = {0.0f, 0.0f, dstwidth, dstheight, 0.0f, 1.0f}; thin3d->SetViewports(1, &viewport); thin3d->SetBlendState(thin3d->GetBlendStatePreset(BS_OFF)); Thin3DSamplerState *sampler; if (g_Config.iBufFilter == SCALE_NEAREST) { sampler = thin3d->GetSamplerStatePreset(T3DSamplerStatePreset::SAMPS_NEAREST); } else { sampler = thin3d->GetSamplerStatePreset(T3DSamplerStatePreset::SAMPS_LINEAR); } thin3d->SetSamplerStates(0, 1, &sampler); thin3d->SetDepthStencilState(depth); thin3d->SetRenderState(T3DRenderState::CULL_MODE, T3DCullMode::NO_CULL); thin3d->SetScissorEnabled(false); float u0 = 0.0f; float u1; if (displayFramebuf_ == 0) { u8 data[] = {0, 0, 0, 0}; fbTex->SetImageData(0, 0, 0, 1, 1, 1, 0, 4, data); u1 = 1.0f; } else if (displayFormat_ == GE_FORMAT_8888) { u8 *data = Memory::GetPointer(displayFramebuf_); fbTex->SetImageData(0, 0, 0, displayStride_, srcheight, 1, 0, displayStride_ * 4, data); u1 = (float)srcwidth / displayStride_; } else { // TODO: This should probably be converted in a shader instead.. fbTexBuffer.resize(srcwidth * srcheight); FormatBuffer displayBuffer; displayBuffer.data = Memory::GetPointer(displayFramebuf_); for (int y = 0; y < srcheight; ++y) { u32 *buf_line = &fbTexBuffer[y * srcwidth]; const u16 *fb_line = &displayBuffer.as16[y * displayStride_]; switch (displayFormat_) { case GE_FORMAT_565: ConvertRGBA565ToRGBA8888(buf_line, fb_line, srcwidth); break; case GE_FORMAT_5551: ConvertRGBA5551ToRGBA8888(buf_line, fb_line, srcwidth); break; case GE_FORMAT_4444: ConvertRGBA4444ToRGBA8888(buf_line, fb_line, srcwidth); break; default: ERROR_LOG_REPORT(G3D, "Software: Unexpected framebuffer format: %d", displayFormat_); } } fbTex->SetImageData(0, 0, 0, srcwidth, srcheight, 1, 0, srcwidth * 4, (const uint8_t *)&fbTexBuffer[0]); u1 = 1.0f; } fbTex->Finalize(0); float x, y, w, h; CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL); if (GetGPUBackend() == GPUBackend::DIRECT3D9) { x += 0.5f; y += 0.5f; } 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; struct Vertex { float x, y, z; float u, v; uint32_t rgba; }; float v0 = 1.0f; float v1 = 0.0f; if (GetGPUBackend() == GPUBackend::VULKAN) { std::swap(v0, v1); } const Vertex verts[4] = { {x, y, 0, u0, v0, 0xFFFFFFFF}, // TL {x, y2, 0, u0, v1, 0xFFFFFFFF}, // BL {x2, y2, 0, u1, v1, 0xFFFFFFFF}, // BR {x2, y, 0, u1, v0, 0xFFFFFFFF}, // TR }; vdata->SetData((const uint8_t *)verts, sizeof(verts)); int indexes[] = {0, 1, 2, 0, 2, 3}; idata->SetData((const uint8_t *)indexes, sizeof(indexes)); thin3d->SetTexture(0, fbTex); Thin3DShaderSet *texColor = thin3d->GetShaderSetPreset(SS_TEXTURE_COLOR_2D); static const float identity4x4[16] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; texColor->SetMatrix4x4("WorldViewProj", identity4x4); thin3d->DrawIndexed(T3DPrimitive::PRIM_TRIANGLES, texColor, vformat, vdata, idata, 6, 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; glDisable(GL_BLEND); glViewport(0, 0, dstwidth, dstheight); glDisable(GL_SCISSOR_TEST); 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] = RGB565ToRGBA8888(fb_line[x]); } break; case GE_FORMAT_5551: for (int x = 0; x < srcwidth; ++x) { buf_line[x] = RGBA5551ToRGBA8888(fb_line[x]); } break; case GE_FORMAT_4444: for (int x = 0; x < srcwidth; ++x) { buf_line[x] = RGBA4444ToRGBA8888(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; CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, dstwidth, dstheight, ROTATION_LOCKED_HORIZONTAL); 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} }; if (vao != 0) { glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbuf); glBufferData(GL_ARRAY_BUFFER, sizeof(verts) + sizeof(texverts), nullptr, GL_STREAM_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verts), verts); glBufferSubData(GL_ARRAY_BUFFER, sizeof(verts), sizeof(texverts), texverts); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, 0, 0); glVertexAttribPointer(attr_tex, 2, GL_FLOAT, GL_FALSE, 0, (void *)sizeof(verts)); } else { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 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); if (vao != 0) { glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } }