Skip to content

Commit

Permalink
opengl: faster 24bit mode without downgrading quality
Browse files Browse the repository at this point in the history
remove GL_FLOAT fallback, moved to GL_UNSIGNED_SHORT_5_5_5_1
  • Loading branch information
JaCzekanski committed Sep 9, 2019
1 parent 9ea1cac commit 7b39949
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 96 deletions.
3 changes: 3 additions & 0 deletions src/device/gpu/psx_color.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <cstdint>
#include <glm/glm.hpp>
#include "utils/macros.h"
#include "utils/math.h"

// Union for storing 24bit color (used in GPU commands)
Expand All @@ -27,6 +28,8 @@ union PSXColor {
};
uint16_t raw;

INLINE uint16_t rev() const { return (r << 11) | (g << 6) | (b << 1) | k; }

PSXColor() : raw(0) {}
PSXColor(uint16_t color) : raw(color) {}
PSXColor(uint8_t r, uint8_t g, uint8_t b) {
Expand Down
12 changes: 6 additions & 6 deletions src/platform/windows/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ int main(int argc, char** argv) {

SDL_GameControllerAddMappingsFromFile("data/assets/gamecontrollerdb.txt");

OpenGL opengl;
auto opengl = std::make_unique<OpenGL>();

SDL_Window* window = SDL_CreateWindow("Avocado", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, OpenGL::resWidth, OpenGL::resHeight,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI);
Expand All @@ -295,7 +295,7 @@ int main(int argc, char** argv) {
return 1;
}

if (!opengl.setup()) {
if (!opengl->setup()) {
fatalError("Cannot setup graphics");
return 1;
}
Expand Down Expand Up @@ -450,8 +450,8 @@ int main(int argc, char** argv) {
}
if (event.type == SDL_WINDOWEVENT
&& (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED || event.window.event == SDL_WINDOWEVENT_RESIZED)) {
opengl.width = event.window.data1;
opengl.height = event.window.data2;
opengl->width = event.window.data1;
opengl->height = event.window.data2;
}

// Crude hack to force next frame after last event received (in paused mode)
Expand All @@ -478,8 +478,8 @@ int main(int argc, char** argv) {
ImGui_ImplSDL2_NewFrame(window);
ImGui::NewFrame();

SDL_GL_GetDrawableSize(window, &opengl.width, &opengl.height);
opengl.render(sys->gpu.get());
SDL_GL_GetDrawableSize(window, &opengl->width, &opengl->height);
opengl->render(sys->gpu.get());

renderImgui(sys.get());
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
Expand Down
136 changes: 47 additions & 89 deletions src/renderer/opengl/opengl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,28 @@ bool OpenGL::setup() {

blitBuffer = std::make_unique<Buffer>(makeBlitBuf().size() * sizeof(BlitStruct));

// Try native texture

vramTex.release();

// Try native texture
#ifdef GL_UNSIGNED_SHORT_1_5_5_5_REV
vramTex = std::make_unique<Texture>(1024, 512, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false);
vramTex = std::make_unique<Texture>(gpu::VRAM_WIDTH, gpu::VRAM_HEIGHT, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false);
#endif

if (vramTex && vramTex->isCreated()) {
supportNativeTexture = true;
} else {
// Use compability mode
vramTex = std::make_unique<Texture>(1024, 512, GL_RGBA, GL_RGBA, GL_FLOAT, false);
vramTex = std::make_unique<Texture>(gpu::VRAM_WIDTH, gpu::VRAM_HEIGHT, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, false);
if (!vramTex || !vramTex->isCreated()) {
fmt::print("[GL] Unable to create VRAM texture\n");
return false;
}
supportNativeTexture = false;
}

// Texture for 24bit mode
vram24Tex = std::make_unique<Texture>(gpu::VRAM_WIDTH, gpu::VRAM_HEIGHT, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, false);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(0);
Expand Down Expand Up @@ -175,110 +182,58 @@ void OpenGL::bindCopyAttributes() {
}

void OpenGL::update24bitTexture(gpu::GPU* gpu) {
// Hack: 24 bit is degraded to 15bit native texture here
if (supportNativeTexture) {
size_t dataSize = gpu::VRAM_HEIGHT * gpu::VRAM_WIDTH;
static std::vector<uint16_t> vram24Unpacked;
if (vram24Unpacked.size() != dataSize) {
vram24Unpacked.resize(dataSize);
}

// Unpack VRAM to native GPU format (4x float)
for (int y = 0; y < gpu::VRAM_HEIGHT; y++) {
for (int x = 0; x < gpu::VRAM_WIDTH; x++) {
int xMasked = (x / 2) * 3;
uint16_t col;
if (x % 2 == 0) {
uint16_t c1 = gpu->vram[y * gpu::VRAM_WIDTH + xMasked + 0];
uint16_t c2 = gpu->vram[y * gpu::VRAM_WIDTH + xMasked + 1];

uint8_t r = (c1 & 0x00ff) >> 0;
uint8_t g = (c1 & 0xff00) >> 8;
uint8_t b = (c2 & 0x00ff) >> 0;

col = to15bit(r, g, b);

} else {
uint16_t c1 = gpu->vram[y * gpu::VRAM_WIDTH + xMasked + 1];
uint16_t c2 = gpu->vram[y * gpu::VRAM_WIDTH + xMasked + 2];

uint8_t r = (c1 & 0xff00) >> 8;
uint8_t g = (c2 & 0x00ff) >> 0;
uint8_t b = (c2 & 0xff00) >> 8;

col = to15bit(r, g, b);
}

vram24Unpacked[(y * gpu::VRAM_WIDTH + x)] = col;
}
}
vramTex->update(vram24Unpacked.data());
return;
}

size_t dataSize = gpu::VRAM_HEIGHT * gpu::VRAM_WIDTH * 4;
if (vramUnpacked.size() != dataSize) {
vramUnpacked.resize(dataSize);
size_t dataSize = gpu::VRAM_HEIGHT * gpu::VRAM_WIDTH * 3;
if (vram24Unpacked.size() != dataSize) {
vram24Unpacked.resize(dataSize);
}

// Unpack VRAM to native GPU format (4x float)
// Unpack VRAM to 8 bit RGB values (two pixels at the time)
for (int y = 0; y < gpu::VRAM_HEIGHT; y++) {
for (int x = 0; x < gpu::VRAM_WIDTH; x++) {
int xMasked = (x / 2) * 3;
if (x % 2 == 0) {
uint16_t c1 = gpu->vram[y * gpu::VRAM_WIDTH + xMasked + 0];
uint16_t c2 = gpu->vram[y * gpu::VRAM_WIDTH + xMasked + 1];

vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 0] = ((c1 & 0x00ff) >> 0) / 255.f;
vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 1] = ((c1 & 0xff00) >> 8) / 255.f;
vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 2] = ((c2 & 0x00ff) >> 0) / 255.f;
vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 3] = 1.0;
} else {
uint16_t c1 = gpu->vram[y * gpu::VRAM_WIDTH + xMasked + 1];
uint16_t c2 = gpu->vram[y * gpu::VRAM_WIDTH + xMasked + 2];

vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 0] = ((c1 & 0xff00) >> 8) / 255.f;
vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 1] = ((c2 & 0x00ff) >> 0) / 255.f;
vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 2] = ((c2 & 0xff00) >> 8) / 255.f;
vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 3] = 1.0;
}
unsigned int gpuOffset = y * gpu::VRAM_WIDTH;
unsigned int texOffset = y * gpu::VRAM_WIDTH * 3;
for (int x = 0; x < gpu::VRAM_WIDTH; x += 3) {
uint16_t c1 = gpu->vram[gpuOffset + 0];
uint16_t c2 = gpu->vram[gpuOffset + 1];
uint16_t c3 = gpu->vram[gpuOffset + 2];

uint8_t r0 = (c1 & 0x00ff) >> 0;
uint8_t g0 = (c1 & 0xff00) >> 8;
uint8_t b0 = (c2 & 0x00ff) >> 0;
uint8_t r1 = (c2 & 0xff00) >> 8;
uint8_t g1 = (c3 & 0x00ff) >> 0;
uint8_t b1 = (c3 & 0xff00) >> 8;

vram24Unpacked[texOffset + 0] = r0;
vram24Unpacked[texOffset + 1] = g0;
vram24Unpacked[texOffset + 2] = b0;
vram24Unpacked[texOffset + 3] = r1;
vram24Unpacked[texOffset + 4] = g1;
vram24Unpacked[texOffset + 5] = b1;

gpuOffset += 3;
texOffset += 6;
}
}

vramTex->update(vramUnpacked.data());
}

constexpr std::array<float, 32> generateFloatLUT() {
std::array<float, 32> lut = {{0}};
for (int i = 0; i < 32; i++) {
lut[i] = i / 31.f;
}
return lut;
vram24Tex->update(vram24Unpacked.data());
}

const std::array<float, 32> floatLUT = generateFloatLUT();

void OpenGL::updateVramTexture(gpu::GPU* gpu) {
if (supportNativeTexture) {
vramTex->update(gpu->vram.data());
return;
}

size_t dataSize = gpu::VRAM_HEIGHT * gpu::VRAM_WIDTH * 4;
size_t dataSize = gpu::VRAM_HEIGHT * gpu::VRAM_WIDTH;
if (vramUnpacked.size() != dataSize) {
vramUnpacked.resize(dataSize);
}

// TODO: Crash on close!
// Unpack VRAM to native GPU format (4x float)
// Unpack VRAM to native GPU format
for (int y = 0; y < gpu::VRAM_HEIGHT; y++) {
for (int x = 0; x < gpu::VRAM_WIDTH; x++) {
PSXColor c = gpu->vram[y * gpu::VRAM_WIDTH + x];
unsigned int pos = y * gpu::VRAM_WIDTH + x;

vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 0] = floatLUT[c.r];
vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 1] = floatLUT[c.g];
vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 2] = floatLUT[c.b];
vramUnpacked[(y * gpu::VRAM_WIDTH + x) * 4 + 3] = floatLUT[c.k * 31];
vramUnpacked[pos] = PSXColor(gpu->vram[pos]).rev();
}
}
vramTex->update(vramUnpacked.data());
Expand Down Expand Up @@ -511,7 +466,10 @@ void OpenGL::renderBlit(gpu::GPU* gpu, bool software) {
blitBuffer->bind();
bindBlitAttributes();

if (software) {
// Hack
if (gpu->gp1_08.colorDepth == gpu::GP1_08::ColorDepth::bit24) {
vram24Tex->bind(0);
} else if (software) {
vramTex->bind(0);
} else {
renderTex->bind(0);
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/opengl/opengl.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class OpenGL {
std::unique_ptr<Framebuffer> renderFramebuffer;
std::unique_ptr<Texture> renderTex;
std::unique_ptr<Texture> vramTex;
std::unique_ptr<Texture> vram24Tex;
bool supportNativeTexture;

int renderWidth;
Expand All @@ -67,7 +68,8 @@ class OpenGL {
void bindRenderAttributes();
void renderVertices(gpu::GPU* gpu);

std::vector<float> vramUnpacked;
std::vector<uint8_t> vram24Unpacked;
std::vector<uint16_t> vramUnpacked;
void update24bitTexture(gpu::GPU* gpu);
void updateVramTexture(gpu::GPU* gpu);

Expand Down

0 comments on commit 7b39949

Please sign in to comment.