mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-20 17:59:08 +02:00
- Fixes #21739 With the DarkStalkers hack, SoftGPU skips the game's stretch blit and stretches the source image to the screen itself. Libretro always presents software rendering at 480x272, so that stretch happened at 1x and the frontend then scaled up a blurry image. Now libretro gets the 384x224 source as is, with the aspect the game would have stretched it to, and switches back to the full frame when the game stops using the stretch. GL and D3D11 read the frame from a corner of their larger framebuffer. RetroArch's Vulkan driver samples the whole image the core hands it, so the Vulkan presentation images are resized to the frame. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
131 lines
3.5 KiB
C++
131 lines
3.5 KiB
C++
#pragma once
|
|
#include <atomic>
|
|
|
|
#include <libretro.h>
|
|
#include "Common/GPU/GraphicsContext.h"
|
|
#include "Common/GPU/thin3d_create.h"
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Core/Config.h"
|
|
#include "Core/System.h"
|
|
#include "GPU/GPUState.h"
|
|
#include "GPU/Software/SoftGpu.h"
|
|
#include "headless/Compare.h"
|
|
#include "Common/Data/Convert/ColorConv.h"
|
|
|
|
#define NATIVEWIDTH 480
|
|
#define NATIVEHEIGHT 272
|
|
#define SOFT_BMP_SIZE NATIVEWIDTH * NATIVEHEIGHT * 4
|
|
|
|
namespace Libretro {
|
|
// Frame size to hand to video_cb. Normally the backbuffer size (passed in), but smaller when
|
|
// we present a game's source image for the frontend to scale. Updates the geometry when that changes.
|
|
void GetFrameSize(unsigned *width, unsigned *height);
|
|
}
|
|
|
|
class LibretroGraphicsContext : public GraphicsContext {
|
|
public:
|
|
LibretroGraphicsContext() {}
|
|
~LibretroGraphicsContext() override { ShutdownAPI(); }
|
|
|
|
virtual void SetRenderTarget() {}
|
|
virtual GPUCore GetGPUCore() = 0;
|
|
virtual const char *Ident() = 0;
|
|
|
|
void ShutdownAPI() override {
|
|
DestroyDrawContext();
|
|
}
|
|
virtual void SwapBuffers() = 0;
|
|
void Resize() override {}
|
|
// True if ThreadFrame() has queued work to run (emu thread backends only).
|
|
virtual bool ThreadFramePending() { return false; }
|
|
|
|
virtual void GotBackbuffer();
|
|
virtual void LostBackbuffer();
|
|
|
|
virtual void CreateDrawContext() {}
|
|
virtual void DestroyDrawContext() {
|
|
if (!draw_) {
|
|
return;
|
|
}
|
|
delete draw_;
|
|
draw_ = nullptr;
|
|
}
|
|
Draw::DrawContext *GetDrawContext() override { return draw_; }
|
|
|
|
static LibretroGraphicsContext *CreateGraphicsContext();
|
|
|
|
static retro_video_refresh_t video_cb;
|
|
|
|
protected:
|
|
Draw::DrawContext *draw_ = nullptr;
|
|
};
|
|
|
|
class LibretroHWRenderContext : public LibretroGraphicsContext {
|
|
public:
|
|
LibretroHWRenderContext(retro_hw_context_type context_type, unsigned version_major = 0, unsigned version_minor = 0);
|
|
bool InitHW(bool cache_context);
|
|
void SetRenderTarget() override {}
|
|
void SwapBuffers() override {
|
|
unsigned w = PSP_CoreParameter().pixelWidth;
|
|
unsigned h = PSP_CoreParameter().pixelHeight;
|
|
Libretro::GetFrameSize(&w, &h);
|
|
video_cb(RETRO_HW_FRAME_BUFFER_VALID, w, h, 0);
|
|
}
|
|
virtual void ContextReset();
|
|
virtual void ContextDestroy();
|
|
|
|
protected:
|
|
retro_hw_render_callback hw_render_ = {};
|
|
};
|
|
|
|
std::vector<u32> ConvertFramebufferForLibretro(const GPUDebugBuffer *buffer, u32 stride, u32 h);
|
|
|
|
class LibretroSoftwareContext : public LibretroGraphicsContext {
|
|
public:
|
|
LibretroSoftwareContext() {}
|
|
void SwapBuffers() override {
|
|
GPUDebugBuffer buf;
|
|
unsigned w = NATIVEWIDTH;
|
|
unsigned h = NATIVEHEIGHT;
|
|
if (gpu) {
|
|
gpu->GetOutputFramebuffer(buf);
|
|
}
|
|
Libretro::GetFrameSize(&w, &h);
|
|
u32 offset = 0;
|
|
if (w == NATIVEWIDTH && g_Config.bDisplayCropTo16x9) {
|
|
offset = w << 1;
|
|
h -= 2;
|
|
}
|
|
if (gpu) {
|
|
const std::vector<u32> pixels = ConvertFramebufferForLibretro(&buf, w, w == NATIVEWIDTH ? NATIVEHEIGHT : h);
|
|
memcpy(soft_bmp, pixels.data(), pixels.size() * sizeof(u32));
|
|
}
|
|
video_cb(soft_bmp + offset, w, h, w << 2);
|
|
}
|
|
GPUCore GetGPUCore() override { return GPUCORE_SOFTWARE; }
|
|
const char *Ident() override { return "Software"; }
|
|
|
|
u16 soft_bmp[SOFT_BMP_SIZE] = {0};
|
|
};
|
|
|
|
namespace Libretro {
|
|
extern LibretroGraphicsContext *ctx;
|
|
extern retro_environment_t environ_cb;
|
|
extern retro_hw_context_type backend;
|
|
|
|
enum class EmuThreadState {
|
|
DISABLED,
|
|
RUNNING,
|
|
PAUSE_REQUESTED,
|
|
PAUSED,
|
|
QUIT_REQUESTED,
|
|
STOPPED,
|
|
};
|
|
extern bool useEmuThread;
|
|
extern std::atomic<EmuThreadState> emuThreadState;
|
|
void EmuThreadStart();
|
|
void EmuThreadStop();
|
|
void EmuThreadPause();
|
|
} // namespace Libretro
|