move texture cache to a template class. vulkan: OSD on android
store texture in the cache map instead of the heap make related functions member of the class (CollectCleanup, killtex -> Clear) refactor common OSD stuff into rend/osd vulkan support for OSD
This commit is contained in:
parent
2a89874812
commit
86818389ac
|
|
@ -102,7 +102,7 @@ TA_context* _pvrrc;
|
|||
void SetREP(TA_context* cntx);
|
||||
static void rend_create_renderer();
|
||||
|
||||
void dump_frame(const char* file, TA_context* ctx, u8* vram, u8* vram_ref = NULL) {
|
||||
static void dump_frame(const char* file, TA_context* ctx, u8* vram, u8* vram_ref = NULL) {
|
||||
FILE* fw = fopen(file, "wb");
|
||||
|
||||
//append to it
|
||||
|
|
@ -245,7 +245,8 @@ TA_context* read_frame(const char* file, u8* vram_ref = NULL) {
|
|||
|
||||
bool dump_frame_switch = false;
|
||||
|
||||
bool rend_frame(TA_context* ctx, bool draw_osd) {
|
||||
static bool rend_frame(TA_context* ctx)
|
||||
{
|
||||
if (dump_frame_switch) {
|
||||
char name[32];
|
||||
sprintf(name, "dcframe-%d", FrameCount);
|
||||
|
|
@ -267,12 +268,7 @@ bool rend_frame(TA_context* ctx, bool draw_osd) {
|
|||
re.Set();
|
||||
#endif
|
||||
|
||||
bool do_swp = proc && renderer->Render();
|
||||
|
||||
if (do_swp && draw_osd)
|
||||
renderer->DrawOSD(false);
|
||||
|
||||
return do_swp;
|
||||
return proc && renderer->Render();
|
||||
}
|
||||
|
||||
bool rend_single_frame()
|
||||
|
|
@ -332,7 +328,7 @@ bool rend_single_frame()
|
|||
_pvrrc = DequeueRender();
|
||||
}
|
||||
while (!_pvrrc);
|
||||
bool do_swp = rend_frame(_pvrrc, true);
|
||||
bool do_swp = rend_frame(_pvrrc);
|
||||
swap_pending = settings.rend.DelayFrameSwapping && do_swp && !_pvrrc->rend.isRenderFramebuffer;
|
||||
|
||||
#if !defined(TARGET_NO_THREADS)
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ void x11_window_destroy()
|
|||
}
|
||||
cfgSaveBool("x11", "fullscreen", x11_fullscreen);
|
||||
XDestroyWindow(x11_disp, x11_win);
|
||||
x11_win = NULL;
|
||||
x11_win = (Window)0;
|
||||
}
|
||||
if (x11_disp)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#ifndef TARGET_NO_OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
|
@ -7,13 +5,13 @@
|
|||
#include "TexCache.h"
|
||||
#include "hw/pvr/pvr_regs.h"
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
#include "hw/mem/_vmem.h"
|
||||
#include "hw/mem/vmem32.h"
|
||||
#include "hw/sh4/modules/mmu.h"
|
||||
#include "deps/xbrz/xbrz.h"
|
||||
#include <xxhash.h>
|
||||
#include "CustomTexture.h"
|
||||
#include <png.h>
|
||||
|
||||
u8* vq_codebook;
|
||||
u32 palette_index;
|
||||
|
|
@ -733,40 +731,6 @@ void BaseTextureCacheData::CheckCustomTexture()
|
|||
}
|
||||
}
|
||||
|
||||
std::unordered_map<u64, std::unique_ptr<BaseTextureCacheData>> TexCache;
|
||||
|
||||
void CollectCleanup()
|
||||
{
|
||||
vector<u64> list;
|
||||
|
||||
u32 TargetFrame = max((u32)120,FrameCount) - 120;
|
||||
|
||||
for (const auto& pair : TexCache)
|
||||
{
|
||||
if (pair.second->dirty && pair.second->dirty < TargetFrame)
|
||||
list.push_back(pair.first);
|
||||
|
||||
if (list.size() > 5)
|
||||
break;
|
||||
}
|
||||
|
||||
for (u64 id : list)
|
||||
{
|
||||
if (TexCache[id]->Delete())
|
||||
TexCache.erase(id);
|
||||
}
|
||||
}
|
||||
|
||||
void killtex()
|
||||
{
|
||||
for (auto& pair : TexCache)
|
||||
pair.second->Delete();
|
||||
|
||||
TexCache.clear();
|
||||
KillTex = false;
|
||||
INFO_LOG(RENDERER, "Texture cache cleared");
|
||||
}
|
||||
|
||||
void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height)
|
||||
{
|
||||
width = (FB_R_SIZE.fb_x_size + 1) << 1; // in 16-bit words
|
||||
|
|
@ -944,3 +908,147 @@ void rend_text_invl(vram_block* bl)
|
|||
|
||||
libCore_vramlock_Unlock_block_wb(bl);
|
||||
}
|
||||
|
||||
static FILE* pngfile;
|
||||
|
||||
void png_cstd_read(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
if (fread(data, 1, length, pngfile) != length)
|
||||
png_error(png_ptr, "Truncated read error");
|
||||
}
|
||||
|
||||
u8* loadPNGData(const string& fname, int &width, int &height)
|
||||
{
|
||||
const char* filename=fname.c_str();
|
||||
FILE* file = fopen(filename, "rb");
|
||||
pngfile=file;
|
||||
|
||||
if (!file)
|
||||
{
|
||||
EMUERROR("Error opening %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//header for testing if it is a png
|
||||
png_byte header[8];
|
||||
|
||||
//read the header
|
||||
if (fread(header, 1, 8, file) != 8)
|
||||
{
|
||||
fclose(file);
|
||||
WARN_LOG(RENDERER, "Not a PNG file : %s", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//test if png
|
||||
int is_png = !png_sig_cmp(header, 0, 8);
|
||||
if (!is_png)
|
||||
{
|
||||
fclose(file);
|
||||
WARN_LOG(RENDERER, "Not a PNG file : %s", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//create png struct
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
|
||||
NULL, NULL);
|
||||
if (!png_ptr)
|
||||
{
|
||||
fclose(file);
|
||||
WARN_LOG(RENDERER, "Unable to create PNG struct : %s", filename);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
//create png info struct
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
|
||||
WARN_LOG(RENDERER, "Unable to create PNG info : %s", filename);
|
||||
fclose(file);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
//create png info struct
|
||||
png_infop end_info = png_create_info_struct(png_ptr);
|
||||
if (!end_info)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
|
||||
WARN_LOG(RENDERER, "Unable to create PNG end info : %s", filename);
|
||||
fclose(file);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
//png error stuff, not sure libpng man suggests this.
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
fclose(file);
|
||||
WARN_LOG(RENDERER, "Error during setjmp : %s", filename);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
//init png reading
|
||||
//png_init_io(png_ptr, fp);
|
||||
png_set_read_fn(png_ptr, NULL, png_cstd_read);
|
||||
|
||||
//let libpng know you already read the first 8 bytes
|
||||
png_set_sig_bytes(png_ptr, 8);
|
||||
|
||||
// read all the info up to the image data
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
//variables to pass to get info
|
||||
int bit_depth, color_type;
|
||||
png_uint_32 twidth, theight;
|
||||
|
||||
// get info about png
|
||||
png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
//update width and height based on png info
|
||||
width = twidth;
|
||||
height = theight;
|
||||
|
||||
// Update the png info struct.
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
// Row size in bytes.
|
||||
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||
|
||||
// Allocate the image_data as a big block, to be given to opengl
|
||||
png_byte *image_data = new png_byte[rowbytes * height];
|
||||
if (!image_data)
|
||||
{
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
WARN_LOG(RENDERER, "Unable to allocate image_data while loading %s", filename);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//row_pointers is for pointing to image_data for reading the png with libpng
|
||||
png_bytep *row_pointers = new png_bytep[height];
|
||||
if (!row_pointers)
|
||||
{
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
delete[] image_data;
|
||||
WARN_LOG(RENDERER, "Unable to allocate row_pointer while loading %s", filename);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// set the individual row_pointers to point at the correct offsets of image_data
|
||||
for (int i = 0; i < height; ++i)
|
||||
row_pointers[height - 1 - i] = image_data + i * rowbytes;
|
||||
|
||||
//read the png into image_data through row_pointers
|
||||
png_read_image(png_ptr, row_pointers);
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
delete[] row_pointers;
|
||||
fclose(file);
|
||||
|
||||
return image_data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "hw/pvr/pvr_regs.h"
|
||||
#undef ID
|
||||
#include "hw/pvr/ta_structs.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
|
||||
extern u8* vq_codebook;
|
||||
extern u32 palette_index;
|
||||
|
|
@ -706,52 +707,85 @@ struct BaseTextureCacheData
|
|||
virtual ~BaseTextureCacheData() {}
|
||||
};
|
||||
|
||||
extern std::unordered_map<u64, std::unique_ptr<BaseTextureCacheData>> TexCache;
|
||||
typedef std::unordered_map<u64, std::unique_ptr<BaseTextureCacheData>>::iterator TexCacheIter;
|
||||
|
||||
// Only use TexU and TexV from TSP in the cache key
|
||||
// TexV : 7, TexU : 7
|
||||
const TSP TSPTextureCacheMask = { { 7, 7 } };
|
||||
// TexAddr : 0x1FFFFF, Reserved : 0, StrideSel : 0, ScanOrder : 1, PixelFmt : 7, VQ_Comp : 1, MipMapped : 1
|
||||
const TCW TCWTextureCacheMask = { { 0x1FFFFF, 0, 0, 1, 7, 1, 1 } };
|
||||
|
||||
template<typename Func>
|
||||
BaseTextureCacheData *getTextureCacheData(TSP tsp, TCW tcw, Func factory)
|
||||
template<typename Texture>
|
||||
class BaseTextureCache
|
||||
{
|
||||
u64 key = tsp.full & TSPTextureCacheMask.full;
|
||||
if (tcw.PixelFmt == PixelPal4 || tcw.PixelFmt == PixelPal8)
|
||||
// Paletted textures have a palette selection that must be part of the key
|
||||
// We also add the palette type to the key to avoid thrashing the cache
|
||||
// when the palette type is changed. If the palette type is changed back in the future,
|
||||
// this texture will stil be available.
|
||||
key |= ((u64)tcw.full << 32) | ((PAL_RAM_CTRL & 3) << 6);
|
||||
else
|
||||
key |= (u64)(tcw.full & TCWTextureCacheMask.full) << 32;
|
||||
|
||||
TexCacheIter it = TexCache.find(key);
|
||||
|
||||
BaseTextureCacheData* texture;
|
||||
if (it != TexCache.end())
|
||||
using TexCacheIter = typename std::unordered_map<u64, Texture>::iterator;
|
||||
public:
|
||||
Texture *getTextureCacheData(TSP tsp, TCW tcw)
|
||||
{
|
||||
texture = it->second.get();
|
||||
// Needed if the texture is updated
|
||||
texture->tcw.StrideSel = tcw.StrideSel;
|
||||
u64 key = tsp.full & TSPTextureCacheMask.full;
|
||||
if (tcw.PixelFmt == PixelPal4 || tcw.PixelFmt == PixelPal8)
|
||||
// Paletted textures have a palette selection that must be part of the key
|
||||
// We also add the palette type to the key to avoid thrashing the cache
|
||||
// when the palette type is changed. If the palette type is changed back in the future,
|
||||
// this texture will stil be available.
|
||||
key |= ((u64)tcw.full << 32) | ((PAL_RAM_CTRL & 3) << 6);
|
||||
else
|
||||
key |= (u64)(tcw.full & TCWTextureCacheMask.full) << 32;
|
||||
|
||||
TexCacheIter it = cache.find(key);
|
||||
|
||||
Texture* texture;
|
||||
if (it != cache.end())
|
||||
{
|
||||
texture = &it->second;
|
||||
// Needed if the texture is updated
|
||||
texture->tcw.StrideSel = tcw.StrideSel;
|
||||
}
|
||||
else //create if not existing
|
||||
{
|
||||
texture = &cache[key];
|
||||
|
||||
texture->tsp = tsp;
|
||||
texture->tcw = tcw;
|
||||
}
|
||||
texture->Lookups++;
|
||||
|
||||
return texture;
|
||||
}
|
||||
else //create if not existing
|
||||
|
||||
void CollectCleanup()
|
||||
{
|
||||
texture = factory();
|
||||
TexCache[key] = std::unique_ptr<BaseTextureCacheData>(texture);
|
||||
vector<u64> list;
|
||||
|
||||
texture->tsp = tsp;
|
||||
texture->tcw = tcw;
|
||||
u32 TargetFrame = max((u32)120, FrameCount) - 120;
|
||||
|
||||
for (const auto& pair : cache)
|
||||
{
|
||||
if (pair.second.dirty && pair.second.dirty < TargetFrame)
|
||||
list.push_back(pair.first);
|
||||
|
||||
if (list.size() > 5)
|
||||
break;
|
||||
}
|
||||
|
||||
for (u64 id : list)
|
||||
{
|
||||
if (cache[id].Delete())
|
||||
cache.erase(id);
|
||||
}
|
||||
}
|
||||
texture->Lookups++;
|
||||
|
||||
return texture;
|
||||
}
|
||||
void Clear()
|
||||
{
|
||||
for (auto& pair : cache)
|
||||
pair.second.Delete();
|
||||
|
||||
cache.clear();
|
||||
KillTex = false;
|
||||
INFO_LOG(RENDERER, "Texture cache cleared");
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<u64, Texture> cache;
|
||||
// Only use TexU and TexV from TSP in the cache key
|
||||
// TexV : 7, TexU : 7
|
||||
const TSP TSPTextureCacheMask = { { 7, 7 } };
|
||||
// TexAddr : 0x1FFFFF, Reserved : 0, StrideSel : 0, ScanOrder : 1, PixelFmt : 7, VQ_Comp : 1, MipMapped : 1
|
||||
const TCW TCWTextureCacheMask = { { 0x1FFFFF, 0, 0, 1, 7, 1, 1 } };
|
||||
};
|
||||
|
||||
void CollectCleanup();
|
||||
void killtex();
|
||||
void rend_text_invl(vram_block* bl);
|
||||
|
||||
void ReadFramebuffer(PixelBuffer<u32>& pb, int& width, int& height);
|
||||
|
|
@ -766,3 +800,4 @@ static inline void MakeFogTexture(u8 *tex_data)
|
|||
tex_data[i + 128] = fog_table[i * 4 + 1];
|
||||
}
|
||||
}
|
||||
u8* loadPNGData(const string& fname, int &width, int &height);
|
||||
|
|
|
|||
|
|
@ -1001,9 +1001,7 @@ struct gl4rend : Renderer
|
|||
glcache.DeleteTextures(1, &depthSaveTexId);
|
||||
depthSaveTexId = 0;
|
||||
}
|
||||
killtex();
|
||||
|
||||
CollectCleanup();
|
||||
TexCache.Clear();
|
||||
|
||||
gl_free_osd_resources();
|
||||
free_output_framebuffer();
|
||||
|
|
@ -1011,16 +1009,20 @@ struct gl4rend : Renderer
|
|||
}
|
||||
|
||||
bool Process(TA_context* ctx) override { return ProcessFrame(ctx); }
|
||||
bool Render() override { return RenderFrame(); }
|
||||
bool Render() override
|
||||
{
|
||||
RenderFrame();
|
||||
if (!pvrrc.isRTT)
|
||||
DrawOSD(false);
|
||||
|
||||
return !pvrrc.isRTT;
|
||||
}
|
||||
bool RenderLastFrame() override { return !theGLContext.IsSwapBufferPreserved() ? gl4_render_output_framebuffer() : false; }
|
||||
|
||||
void Present() override { theGLContext.Swap(); }
|
||||
|
||||
void DrawOSD(bool clear_screen) override
|
||||
{
|
||||
glBindVertexArray(gl4.vbo.main_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl4.vbo.geometry); glCheck();
|
||||
|
||||
OSD_DRAW(clear_screen);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "rend/gui.h"
|
||||
#include "wsi/gl_context.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "rend/osd.h"
|
||||
|
||||
#ifdef GLES
|
||||
#ifndef GL_RED
|
||||
|
|
@ -381,13 +382,11 @@ out highp vec4 FragColor; \n\
|
|||
\n\
|
||||
in lowp vec4 vtx_base; \n\
|
||||
in mediump vec2 vtx_uv; \n\
|
||||
/* Vertex input*/ \n\
|
||||
\n\
|
||||
uniform sampler2D tex; \n\
|
||||
void main() \n\
|
||||
{ \n\
|
||||
mediump vec2 uv=vtx_uv; \n\
|
||||
uv.y=1.0-uv.y; \n\
|
||||
gl_FragColor = vtx_base*texture(tex,uv.st); \n\
|
||||
gl_FragColor = vtx_base * texture(tex, vtx_uv); \n\
|
||||
}";
|
||||
|
||||
GLCache glcache;
|
||||
|
|
@ -746,7 +745,34 @@ bool CompilePipelineShader( PipelineShader* s)
|
|||
return glIsProgram(s->program)==GL_TRUE;
|
||||
}
|
||||
|
||||
GLuint osd_tex;
|
||||
static void SetupOSDVBO()
|
||||
{
|
||||
#ifndef GLES2
|
||||
if (gl.gl_major >= 3)
|
||||
{
|
||||
if (gl.OSD_SHADER.vao == 0)
|
||||
glGenVertexArrays(1, &gl.OSD_SHADER.vao);
|
||||
glBindVertexArray(gl.OSD_SHADER.vao);
|
||||
}
|
||||
#endif
|
||||
if (gl.OSD_SHADER.geometry == 0)
|
||||
glGenBuffers(1, &gl.OSD_SHADER.geometry);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl.OSD_SHADER.geometry);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
//setup vertex buffers attrib pointers
|
||||
glEnableVertexAttribArray(VERTEX_POS_ARRAY);
|
||||
glVertexAttribPointer(VERTEX_POS_ARRAY, 2, GL_FLOAT, GL_FALSE, sizeof(OSDVertex), (void*)offsetof(OSDVertex, x));
|
||||
|
||||
glEnableVertexAttribArray(VERTEX_COL_BASE_ARRAY);
|
||||
glVertexAttribPointer(VERTEX_COL_BASE_ARRAY, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(OSDVertex), (void*)offsetof(OSDVertex, r));
|
||||
|
||||
glEnableVertexAttribArray(VERTEX_UV_ARRAY);
|
||||
glVertexAttribPointer(VERTEX_UV_ARRAY, 2, GL_FLOAT, GL_FALSE, sizeof(OSDVertex), (void*)offsetof(OSDVertex, u));
|
||||
|
||||
glDisableVertexAttribArray(VERTEX_COL_OFFS_ARRAY);
|
||||
glCheck();
|
||||
}
|
||||
|
||||
void gl_load_osd_resources()
|
||||
{
|
||||
|
|
@ -762,19 +788,26 @@ void gl_load_osd_resources()
|
|||
|
||||
#ifdef __ANDROID__
|
||||
int w, h;
|
||||
if (osd_tex == 0)
|
||||
osd_tex = loadPNG(get_readonly_data_path(DATA_PATH "buttons.png"), w, h);
|
||||
if (gl.OSD_SHADER.osd_tex == 0)
|
||||
gl.OSD_SHADER.osd_tex = loadPNG(get_readonly_data_path(DATA_PATH "buttons.png"), w, h);
|
||||
#endif
|
||||
SetupOSDVBO();
|
||||
}
|
||||
|
||||
void gl_free_osd_resources()
|
||||
{
|
||||
glcache.DeleteProgram(gl.OSD_SHADER.program);
|
||||
|
||||
if (osd_tex != 0) {
|
||||
glcache.DeleteTextures(1, &osd_tex);
|
||||
osd_tex = 0;
|
||||
if (gl.OSD_SHADER.osd_tex != 0) {
|
||||
glcache.DeleteTextures(1, &gl.OSD_SHADER.osd_tex);
|
||||
gl.OSD_SHADER.osd_tex = 0;
|
||||
}
|
||||
glDeleteBuffers(1, &gl.OSD_SHADER.geometry);
|
||||
gl.OSD_SHADER.geometry = 0;
|
||||
#ifndef GLES2
|
||||
glDeleteVertexArrays(1, &gl.OSD_SHADER.vao);
|
||||
gl.OSD_SHADER.vao = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void create_modvol_shader()
|
||||
|
|
@ -893,143 +926,23 @@ void UpdateFogTexture(u8 *fog_table, GLenum texture_slot, GLint fog_image_format
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
|
||||
extern u16 kcode[4];
|
||||
extern u8 rt[4],lt[4];
|
||||
|
||||
#define VJOY_VISIBLE 14
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
extern float vjoy_pos[15][8];
|
||||
#else
|
||||
|
||||
float vjoy_pos[15][8]=
|
||||
{
|
||||
{24+0,24+64,64,64}, //LEFT
|
||||
{24+64,24+0,64,64}, //UP
|
||||
{24+128,24+64,64,64}, //RIGHT
|
||||
{24+64,24+128,64,64}, //DOWN
|
||||
|
||||
{440+0,280+64,64,64}, //X
|
||||
{440+64,280+0,64,64}, //Y
|
||||
{440+128,280+64,64,64}, //B
|
||||
{440+64,280+128,64,64}, //A
|
||||
|
||||
{320-32,360+32,64,64}, //Start
|
||||
|
||||
{440,200,90,64}, //LT
|
||||
{542,200,90,64}, //RT
|
||||
|
||||
{-24,128+224,128,128}, //ANALOG_RING
|
||||
{96,320,64,64}, //ANALOG_POINT
|
||||
{320-32,24,64,64}, // FFORWARD
|
||||
{1} // VJOY_VISIBLE
|
||||
};
|
||||
#endif // !__ANDROID__
|
||||
|
||||
static List<Vertex> osd_vertices;
|
||||
static bool osd_vertices_overrun;
|
||||
|
||||
static const float vjoy_sz[2][15] = {
|
||||
{ 64,64,64,64, 64,64,64,64, 64, 90,90, 128, 64, 64 },
|
||||
{ 64,64,64,64, 64,64,64,64, 64, 64,64, 128, 64, 64 },
|
||||
};
|
||||
|
||||
void HideOSD()
|
||||
{
|
||||
vjoy_pos[VJOY_VISIBLE][0] = 0;
|
||||
}
|
||||
|
||||
static void DrawButton(float* xy, u32 state)
|
||||
{
|
||||
Vertex vtx;
|
||||
|
||||
vtx.z = 1;
|
||||
|
||||
vtx.col[0]=vtx.col[1]=vtx.col[2]=(0x7F-0x40*state/255)*vjoy_pos[VJOY_VISIBLE][0];
|
||||
|
||||
vtx.col[3]=0xA0*vjoy_pos[VJOY_VISIBLE][4];
|
||||
|
||||
vjoy_pos[VJOY_VISIBLE][4]+=(vjoy_pos[VJOY_VISIBLE][0]-vjoy_pos[VJOY_VISIBLE][4])/2;
|
||||
|
||||
|
||||
|
||||
vtx.x = xy[0]; vtx.y = xy[1];
|
||||
vtx.u=xy[4]; vtx.v=xy[5];
|
||||
*osd_vertices.Append() = vtx;
|
||||
|
||||
vtx.x = xy[0] + xy[2]; vtx.y = xy[1];
|
||||
vtx.u=xy[6]; vtx.v=xy[5];
|
||||
*osd_vertices.Append() = vtx;
|
||||
|
||||
vtx.x = xy[0]; vtx.y = xy[1] + xy[3];
|
||||
vtx.u=xy[4]; vtx.v=xy[7];
|
||||
*osd_vertices.Append() = vtx;
|
||||
|
||||
vtx.x = xy[0] + xy[2]; vtx.y = xy[1] + xy[3];
|
||||
vtx.u=xy[6]; vtx.v=xy[7];
|
||||
*osd_vertices.Append() = vtx;
|
||||
}
|
||||
|
||||
static void DrawButton2(float* xy, bool state) { DrawButton(xy,state?0:255); }
|
||||
|
||||
static void osd_gen_vertices()
|
||||
{
|
||||
osd_vertices.Init(ARRAY_SIZE(vjoy_pos) * 4, &osd_vertices_overrun, "OSD vertices");
|
||||
DrawButton2(vjoy_pos[0],kcode[0] & DC_DPAD_LEFT);
|
||||
DrawButton2(vjoy_pos[1],kcode[0] & DC_DPAD_UP);
|
||||
DrawButton2(vjoy_pos[2],kcode[0] & DC_DPAD_RIGHT);
|
||||
DrawButton2(vjoy_pos[3],kcode[0] & DC_DPAD_DOWN);
|
||||
|
||||
DrawButton2(vjoy_pos[4],kcode[0] & DC_BTN_X);
|
||||
DrawButton2(vjoy_pos[5],kcode[0] & DC_BTN_Y);
|
||||
DrawButton2(vjoy_pos[6],kcode[0] & DC_BTN_B);
|
||||
DrawButton2(vjoy_pos[7],kcode[0] & DC_BTN_A);
|
||||
|
||||
DrawButton2(vjoy_pos[8],kcode[0] & DC_BTN_START);
|
||||
|
||||
DrawButton(vjoy_pos[9],lt[0]);
|
||||
|
||||
DrawButton(vjoy_pos[10],rt[0]);
|
||||
|
||||
DrawButton2(vjoy_pos[11],1);
|
||||
DrawButton2(vjoy_pos[12],0);
|
||||
|
||||
DrawButton2(vjoy_pos[13], 0);
|
||||
}
|
||||
|
||||
#define OSD_TEX_W 512
|
||||
#define OSD_TEX_H 256
|
||||
|
||||
void OSD_DRAW(bool clear_screen)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
if (osd_tex == 0)
|
||||
if (gl.OSD_SHADER.osd_tex == 0)
|
||||
gl_load_osd_resources();
|
||||
if (osd_tex != 0)
|
||||
if (gl.OSD_SHADER.osd_tex != 0)
|
||||
{
|
||||
osd_gen_vertices();
|
||||
const std::vector<OSDVertex>& osdVertices = GetOSDVertices();
|
||||
|
||||
float u=0;
|
||||
float v=0;
|
||||
#ifndef GLES2
|
||||
if (gl.gl_major >= 3)
|
||||
glBindVertexArray(gl.OSD_SHADER.vao);
|
||||
else
|
||||
#endif
|
||||
SetupOSDVBO();
|
||||
|
||||
for (int i = 0; i < 14; i++)
|
||||
{
|
||||
//umin,vmin,umax,vmax
|
||||
vjoy_pos[i][4]=(u+1)/OSD_TEX_W;
|
||||
vjoy_pos[i][5]=(v+1)/OSD_TEX_H;
|
||||
|
||||
vjoy_pos[i][6]=((u+vjoy_sz[0][i]-1))/OSD_TEX_W;
|
||||
vjoy_pos[i][7]=((v+vjoy_sz[1][i]-1))/OSD_TEX_H;
|
||||
|
||||
u+=vjoy_sz[0][i];
|
||||
if (u>=OSD_TEX_W)
|
||||
{
|
||||
u-=OSD_TEX_W;
|
||||
v+=vjoy_sz[1][i];
|
||||
}
|
||||
//v+=vjoy_pos[i][3];
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl.OSD_SHADER.geometry);
|
||||
|
||||
verify(glIsProgram(gl.OSD_SHADER.program));
|
||||
glcache.UseProgram(gl.OSD_SHADER.program);
|
||||
|
|
@ -1044,11 +957,11 @@ void OSD_DRAW(bool clear_screen)
|
|||
glUniform4fv(gl.OSD_SHADER.scale, 1, scale);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glcache.BindTexture(GL_TEXTURE_2D, osd_tex);
|
||||
glcache.BindTexture(GL_TEXTURE_2D, gl.OSD_SHADER.osd_tex);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, osd_vertices.bytes(), osd_vertices.head(), GL_STREAM_DRAW); glCheck();
|
||||
glBufferData(GL_ARRAY_BUFFER, osdVertices.size() * sizeof(OSDVertex), osdVertices.data(), GL_STREAM_DRAW); glCheck();
|
||||
|
||||
glcache.Enable(GL_BLEND);
|
||||
glcache.Disable(GL_DEPTH_TEST);
|
||||
|
|
@ -1066,10 +979,12 @@ void OSD_DRAW(bool clear_screen)
|
|||
glcache.ClearColor(0.7f, 0.7f, 0.7f, 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
int dfa = osd_vertices.used() / 4;
|
||||
int dfa = osdVertices.size() / 4;
|
||||
|
||||
for (int i = 0; i < dfa; i++)
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, i * 4, 4);
|
||||
|
||||
glCheck();
|
||||
}
|
||||
#endif
|
||||
gui_display_osd();
|
||||
|
|
@ -1080,7 +995,7 @@ bool ProcessFrame(TA_context* ctx)
|
|||
ctx->rend_inuse.Lock();
|
||||
|
||||
if (KillTex)
|
||||
killtex();
|
||||
TexCache.Clear();
|
||||
|
||||
if (ctx->rend.isRenderFramebuffer)
|
||||
{
|
||||
|
|
@ -1092,7 +1007,7 @@ bool ProcessFrame(TA_context* ctx)
|
|||
if (!ta_parse_vdrc(ctx))
|
||||
return false;
|
||||
}
|
||||
CollectCleanup();
|
||||
TexCache.CollectCleanup();
|
||||
|
||||
if (ctx->rend.Overrun)
|
||||
WARN_LOG(PVR, "ERROR: TA context overrun");
|
||||
|
|
@ -1575,33 +1490,25 @@ struct glesrend : Renderer
|
|||
void Resize(int w, int h) override { screen_width=w; screen_height=h; }
|
||||
void Term() override
|
||||
{
|
||||
killtex();
|
||||
TexCache.Clear();
|
||||
gles_term();
|
||||
}
|
||||
|
||||
bool Process(TA_context* ctx) override { return ProcessFrame(ctx); }
|
||||
bool Render() override { return RenderFrame(); }
|
||||
bool Render() override
|
||||
{
|
||||
RenderFrame();
|
||||
if (!pvrrc.isRTT)
|
||||
DrawOSD(false);
|
||||
|
||||
return !pvrrc.isRTT;
|
||||
}
|
||||
bool RenderLastFrame() override { return !theGLContext.IsSwapBufferPreserved() ? render_output_framebuffer() : false; }
|
||||
void Present() override { theGLContext.Swap(); glViewport(0, 0, screen_width, screen_height); }
|
||||
|
||||
void DrawOSD(bool clear_screen) override
|
||||
{
|
||||
#ifndef GLES2
|
||||
if (gl.gl_major >= 3)
|
||||
glBindVertexArray(gl.vbo.vao);
|
||||
#endif
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl.vbo.geometry);
|
||||
glEnableVertexAttribArray(VERTEX_POS_ARRAY);
|
||||
glVertexAttribPointer(VERTEX_POS_ARRAY, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex,x));
|
||||
|
||||
glEnableVertexAttribArray(VERTEX_COL_BASE_ARRAY);
|
||||
glVertexAttribPointer(VERTEX_COL_BASE_ARRAY, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex,col));
|
||||
|
||||
glEnableVertexAttribArray(VERTEX_UV_ARRAY);
|
||||
glVertexAttribPointer(VERTEX_UV_ARRAY, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex,u));
|
||||
|
||||
OSD_DRAW(clear_screen);
|
||||
glCheck();
|
||||
}
|
||||
|
||||
virtual u64 GetTexture(TSP tsp, TCW tcw) override
|
||||
|
|
@ -1611,150 +1518,6 @@ struct glesrend : Renderer
|
|||
};
|
||||
|
||||
|
||||
FILE* pngfile;
|
||||
|
||||
void png_cstd_read(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
if (fread(data, 1, length, pngfile) != length)
|
||||
png_error(png_ptr, "Truncated read error");
|
||||
}
|
||||
|
||||
u8* loadPNGData(const string& fname, int &width, int &height)
|
||||
{
|
||||
const char* filename=fname.c_str();
|
||||
FILE* file = fopen(filename, "rb");
|
||||
pngfile=file;
|
||||
|
||||
if (!file)
|
||||
{
|
||||
EMUERROR("Error opening %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//header for testing if it is a png
|
||||
png_byte header[8];
|
||||
|
||||
//read the header
|
||||
if (fread(header, 1, 8, file) != 8)
|
||||
{
|
||||
fclose(file);
|
||||
WARN_LOG(RENDERER, "Not a PNG file : %s", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//test if png
|
||||
int is_png = !png_sig_cmp(header, 0, 8);
|
||||
if (!is_png)
|
||||
{
|
||||
fclose(file);
|
||||
WARN_LOG(RENDERER, "Not a PNG file : %s", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//create png struct
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
|
||||
NULL, NULL);
|
||||
if (!png_ptr)
|
||||
{
|
||||
fclose(file);
|
||||
WARN_LOG(RENDERER, "Unable to create PNG struct : %s", filename);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
//create png info struct
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
|
||||
WARN_LOG(RENDERER, "Unable to create PNG info : %s", filename);
|
||||
fclose(file);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
//create png info struct
|
||||
png_infop end_info = png_create_info_struct(png_ptr);
|
||||
if (!end_info)
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
|
||||
WARN_LOG(RENDERER, "Unable to create PNG end info : %s", filename);
|
||||
fclose(file);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
//png error stuff, not sure libpng man suggests this.
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
fclose(file);
|
||||
WARN_LOG(RENDERER, "Error during setjmp : %s", filename);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
//init png reading
|
||||
//png_init_io(png_ptr, fp);
|
||||
png_set_read_fn(png_ptr, NULL, png_cstd_read);
|
||||
|
||||
//let libpng know you already read the first 8 bytes
|
||||
png_set_sig_bytes(png_ptr, 8);
|
||||
|
||||
// read all the info up to the image data
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
//variables to pass to get info
|
||||
int bit_depth, color_type;
|
||||
png_uint_32 twidth, theight;
|
||||
|
||||
// get info about png
|
||||
png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
//update width and height based on png info
|
||||
width = twidth;
|
||||
height = theight;
|
||||
|
||||
// Update the png info struct.
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
// Row size in bytes.
|
||||
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
|
||||
|
||||
// Allocate the image_data as a big block, to be given to opengl
|
||||
png_byte *image_data = new png_byte[rowbytes * height];
|
||||
if (!image_data)
|
||||
{
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
WARN_LOG(RENDERER, "Unable to allocate image_data while loading %s", filename);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//row_pointers is for pointing to image_data for reading the png with libpng
|
||||
png_bytep *row_pointers = new png_bytep[height];
|
||||
if (!row_pointers)
|
||||
{
|
||||
//clean up memory and close stuff
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
delete[] image_data;
|
||||
WARN_LOG(RENDERER, "Unable to allocate row_pointer while loading %s", filename);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// set the individual row_pointers to point at the correct offsets of image_data
|
||||
for (int i = 0; i < height; ++i)
|
||||
row_pointers[height - 1 - i] = image_data + i * rowbytes;
|
||||
|
||||
//read the png into image_data through row_pointers
|
||||
png_read_image(png_ptr, row_pointers);
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
delete[] row_pointers;
|
||||
fclose(file);
|
||||
|
||||
return image_data;
|
||||
}
|
||||
|
||||
GLuint loadPNG(const string& fname, int &width, int &height)
|
||||
{
|
||||
png_byte *image_data = loadPNGData(fname, width, height);
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@ struct gl_ctx
|
|||
{
|
||||
GLuint program;
|
||||
GLuint scale;
|
||||
GLuint vao;
|
||||
GLuint geometry;
|
||||
GLuint osd_tex;
|
||||
} OSD_SHADER;
|
||||
|
||||
struct
|
||||
|
|
@ -200,4 +203,9 @@ struct TextureCacheData : BaseTextureCacheData
|
|||
virtual bool Delete() override;
|
||||
};
|
||||
|
||||
class TextureCache : public BaseTextureCache<TextureCacheData>
|
||||
{
|
||||
};
|
||||
extern TextureCache TexCache;
|
||||
|
||||
extern const u32 Zfunction[8];
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ Compression
|
|||
#endif
|
||||
|
||||
extern u32 decoded_colors[3][65536];
|
||||
TextureCache TexCache;
|
||||
|
||||
static void dumpRtTexture(u32 name, u32 w, u32 h) {
|
||||
char sname[256];
|
||||
|
|
@ -319,7 +320,7 @@ void ReadRTTBuffer() {
|
|||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8 << tsp.TexU) < w; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8 << tsp.TexV) < h; tsp.TexV++);
|
||||
|
||||
TextureCacheData *texture_data = static_cast<TextureCacheData*>(getTextureCacheData(tsp, tcw, [](){ return (BaseTextureCacheData *)new TextureCacheData(); }));
|
||||
TextureCacheData *texture_data = TexCache.getTextureCacheData(tsp, tcw);
|
||||
if (texture_data->texID != 0)
|
||||
glcache.DeleteTextures(1, &texture_data->texID);
|
||||
else
|
||||
|
|
@ -345,7 +346,7 @@ u64 gl_GetTexture(TSP tsp, TCW tcw)
|
|||
TexCacheLookups++;
|
||||
|
||||
//lookup texture
|
||||
TextureCacheData* tf = static_cast<TextureCacheData*>(getTextureCacheData(tsp, tcw, [](){ return (BaseTextureCacheData *)new TextureCacheData(); }));
|
||||
TextureCacheData* tf = TexCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->texID == 0)
|
||||
{
|
||||
|
|
@ -380,7 +381,7 @@ text_info raw_GetTexture(TSP tsp, TCW tcw)
|
|||
text_info rv = { 0 };
|
||||
|
||||
//lookup texture
|
||||
TextureCacheData* tf = static_cast<TextureCacheData*>(getTextureCacheData(tsp, tcw, [](){ return (BaseTextureCacheData *)new TextureCacheData(); }));
|
||||
TextureCacheData* tf = TexCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->pData == nullptr)
|
||||
tf->Create();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
// Personal message to whoever wrote this code originally: please quit programming. Stop making other people's life miserable
|
||||
|
||||
#include "osd.h"
|
||||
#include "types.h"
|
||||
#include "input/gamepad.h"
|
||||
|
||||
extern u16 kcode[4];
|
||||
extern u8 rt[4], lt[4];
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
extern float vjoy_pos[15][8];
|
||||
#else
|
||||
|
||||
static float vjoy_pos[15][8]=
|
||||
{
|
||||
{24+0,24+64,64,64}, //LEFT
|
||||
{24+64,24+0,64,64}, //UP
|
||||
{24+128,24+64,64,64}, //RIGHT
|
||||
{24+64,24+128,64,64}, //DOWN
|
||||
|
||||
{440+0,280+64,64,64}, //X
|
||||
{440+64,280+0,64,64}, //Y
|
||||
{440+128,280+64,64,64}, //B
|
||||
{440+64,280+128,64,64}, //A
|
||||
|
||||
{320-32,360+32,64,64}, //Start
|
||||
|
||||
{440,200,90,64}, //LT
|
||||
{542,200,90,64}, //RT
|
||||
|
||||
{-24,128+224,128,128}, //ANALOG_RING
|
||||
{96,320,64,64}, //ANALOG_POINT
|
||||
{320-32,24,64,64}, // FFORWARD
|
||||
{1} // VJOY_VISIBLE
|
||||
};
|
||||
#endif // !__ANDROID__
|
||||
|
||||
static const float vjoy_sz[2][15] = {
|
||||
{ 64,64,64,64, 64,64,64,64, 64, 90,90, 128, 64, 64 },
|
||||
{ 64,64,64,64, 64,64,64,64, 64, 64,64, 128, 64, 64 },
|
||||
};
|
||||
|
||||
static std::vector<OSDVertex> osdVertices;
|
||||
|
||||
void HideOSD()
|
||||
{
|
||||
vjoy_pos[VJOY_VISIBLE][0] = 0;
|
||||
}
|
||||
|
||||
static void DrawButton(const float xy[8], u32 state)
|
||||
{
|
||||
OSDVertex vtx;
|
||||
|
||||
vtx.r = vtx.g = vtx.b = (0x7F - 0x40 * state / 255) * vjoy_pos[VJOY_VISIBLE][0];
|
||||
vtx.a = 0xA0 * vjoy_pos[VJOY_VISIBLE][4];
|
||||
vjoy_pos[VJOY_VISIBLE][4] += (vjoy_pos[VJOY_VISIBLE][0] - vjoy_pos[VJOY_VISIBLE][4]) / 2;
|
||||
|
||||
vtx.x = xy[0]; vtx.y = xy[1];
|
||||
vtx.u = xy[4]; vtx.v = xy[5];
|
||||
osdVertices.push_back(vtx);
|
||||
|
||||
vtx.x = xy[0] + xy[2]; vtx.y = xy[1];
|
||||
vtx.u = xy[6]; vtx.v = xy[5];
|
||||
osdVertices.push_back(vtx);
|
||||
|
||||
vtx.x = xy[0]; vtx.y = xy[1] + xy[3];
|
||||
vtx.u = xy[4]; vtx.v = xy[7];
|
||||
osdVertices.push_back(vtx);
|
||||
|
||||
vtx.x = xy[0] + xy[2]; vtx.y = xy[1] + xy[3];
|
||||
vtx.u = xy[6]; vtx.v = xy[7];
|
||||
osdVertices.push_back(vtx);
|
||||
}
|
||||
|
||||
static void DrawButton2(const float xy[8], bool state)
|
||||
{
|
||||
DrawButton(xy, state ? 0 : 255);
|
||||
}
|
||||
|
||||
const std::vector<OSDVertex>& GetOSDVertices()
|
||||
{
|
||||
osdVertices.reserve(ARRAY_SIZE(vjoy_pos) * 4);
|
||||
osdVertices.clear();
|
||||
DrawButton2(vjoy_pos[0], kcode[0] & DC_DPAD_LEFT);
|
||||
DrawButton2(vjoy_pos[1], kcode[0] & DC_DPAD_UP);
|
||||
DrawButton2(vjoy_pos[2], kcode[0] & DC_DPAD_RIGHT);
|
||||
DrawButton2(vjoy_pos[3], kcode[0] & DC_DPAD_DOWN);
|
||||
|
||||
DrawButton2(vjoy_pos[4], kcode[0] & DC_BTN_X);
|
||||
DrawButton2(vjoy_pos[5], kcode[0] & DC_BTN_Y);
|
||||
DrawButton2(vjoy_pos[6], kcode[0] & DC_BTN_B);
|
||||
DrawButton2(vjoy_pos[7], kcode[0] & DC_BTN_A);
|
||||
|
||||
DrawButton2(vjoy_pos[8], kcode[0] & DC_BTN_START);
|
||||
|
||||
DrawButton(vjoy_pos[9], lt[0]);
|
||||
|
||||
DrawButton(vjoy_pos[10], rt[0]);
|
||||
|
||||
DrawButton2(vjoy_pos[11], 1);
|
||||
DrawButton2(vjoy_pos[12], 0);
|
||||
|
||||
DrawButton2(vjoy_pos[13], 0);
|
||||
|
||||
return osdVertices;
|
||||
}
|
||||
|
||||
static void setVjoyUV()
|
||||
{
|
||||
float u = 0;
|
||||
float v = 0;
|
||||
|
||||
for (int i = 0; i < VJOY_VISIBLE; i++)
|
||||
{
|
||||
//umin, vmin, umax, vmax
|
||||
vjoy_pos[i][4] = (u + 1) / OSD_TEX_W;
|
||||
vjoy_pos[i][5] = 1.f - (v + 1) / OSD_TEX_H;
|
||||
|
||||
vjoy_pos[i][6] = (u + vjoy_sz[0][i] - 1) / OSD_TEX_W;
|
||||
vjoy_pos[i][7] = 1.f - (v + vjoy_sz[1][i] - 1) / OSD_TEX_H;
|
||||
|
||||
u += vjoy_sz[0][i];
|
||||
if (u >= OSD_TEX_W)
|
||||
{
|
||||
u -= OSD_TEX_W;
|
||||
v += vjoy_sz[1][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static OnLoad setVjoyUVOnLoad(&setVjoyUV);
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#include <vector>
|
||||
#include "types.h"
|
||||
|
||||
#define VJOY_VISIBLE 14
|
||||
#define OSD_TEX_W 512
|
||||
#define OSD_TEX_H 256
|
||||
|
||||
struct OSDVertex
|
||||
{
|
||||
float x, y;
|
||||
float u, v;
|
||||
u8 r, g, b, a;
|
||||
};
|
||||
|
||||
const std::vector<OSDVertex>& GetOSDVertices();
|
||||
|
|
@ -36,7 +36,7 @@ struct BufferData
|
|||
void upload(vk::Device const& device, u32 size, const void *data, u32 bufOffset = 0) const
|
||||
{
|
||||
verify((m_propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent) && (m_propertyFlags & vk::MemoryPropertyFlagBits::eHostVisible));
|
||||
verify(offset + bufOffset + size <= bufferSize);
|
||||
verify(bufOffset + size <= bufferSize);
|
||||
|
||||
void* dataPtr = device.mapMemory(sharedDeviceMemory, offset + bufOffset, size);
|
||||
memcpy(dataPtr, data, size);
|
||||
|
|
@ -50,7 +50,7 @@ struct BufferData
|
|||
u32 totalSize = 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
totalSize += sizes[i];
|
||||
verify(offset + bufOffset + totalSize <= bufferSize);
|
||||
verify(bufOffset + totalSize <= bufferSize);
|
||||
void* dataPtr = device.mapMemory(sharedDeviceMemory, offset + bufOffset, totalSize);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
|
|
@ -64,7 +64,7 @@ struct BufferData
|
|||
void download(vk::Device const& device, u32 size, void *data, u32 bufOffset = 0) const
|
||||
{
|
||||
verify((m_propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent) && (m_propertyFlags & vk::MemoryPropertyFlagBits::eHostVisible));
|
||||
verify(offset + bufOffset + size <= bufferSize);
|
||||
verify(bufOffset + size <= bufferSize);
|
||||
|
||||
void* dataPtr = device.mapMemory(sharedDeviceMemory, offset + bufOffset, size);
|
||||
memcpy(data, dataPtr, size);
|
||||
|
|
|
|||
|
|
@ -448,8 +448,6 @@ bool Drawer::Draw(const Texture *fogTexture)
|
|||
if (!is_rtt)
|
||||
gui_display_osd();
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
return !is_rtt;
|
||||
}
|
||||
|
||||
|
|
@ -477,7 +475,7 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass()
|
|||
heightPow2 *= settings.rend.RenderToTextureUpscale;
|
||||
}
|
||||
|
||||
static_cast<RttPipelineManager*>(pipelineManager.get())->CheckSettingsChange();
|
||||
static_cast<RttPipelineManager*>(pipelineManager)->CheckSettingsChange();
|
||||
VulkanContext *context = GetContext();
|
||||
vk::Device device = *context->GetDevice();
|
||||
|
||||
|
|
@ -514,11 +512,14 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass()
|
|||
for (tsp.TexU = 0; tsp.TexU <= 7 && (8 << tsp.TexU) < origWidth; tsp.TexU++);
|
||||
for (tsp.TexV = 0; tsp.TexV <= 7 && (8 << tsp.TexV) < origHeight; tsp.TexV++);
|
||||
|
||||
texture = static_cast<Texture*>(getTextureCacheData(tsp, tcw, [this](){
|
||||
return (BaseTextureCacheData *)new Texture(VulkanContext::Instance()->GetPhysicalDevice(), *VulkanContext::Instance()->GetDevice(), this->texAllocator);
|
||||
}));
|
||||
texture = textureCache->getTextureCacheData(tsp, tcw);
|
||||
if (texture->IsNew())
|
||||
{
|
||||
texture->Create();
|
||||
texture->SetAllocator(texAllocator);
|
||||
texture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
texture->SetDevice(*GetContext()->GetDevice());
|
||||
}
|
||||
if (texture->format != vk::Format::eR8G8B8A8Unorm)
|
||||
{
|
||||
texture->extent = vk::Extent2D(widthPow2, heightPow2);
|
||||
|
|
|
|||
|
|
@ -56,17 +56,17 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void Init(SamplerManager *samplerManager, ShaderManager *shaderManager)
|
||||
void Init(SamplerManager *samplerManager, PipelineManager *pipelineManager)
|
||||
{
|
||||
this->pipelineManager = pipelineManager;
|
||||
this->samplerManager = samplerManager;
|
||||
pipelineManager->Init(shaderManager);
|
||||
}
|
||||
virtual DescriptorSets& GetCurrentDescSet() = 0;
|
||||
virtual BufferData *GetMainBuffer(u32 size) = 0;
|
||||
|
||||
VulkanContext *GetContext() const { return VulkanContext::Instance(); }
|
||||
|
||||
std::unique_ptr<PipelineManager> pipelineManager;
|
||||
PipelineManager *pipelineManager = nullptr;
|
||||
vk::Rect2D baseScissor;
|
||||
// temp stuff
|
||||
float scale_x = 1.f;
|
||||
|
|
@ -106,9 +106,10 @@ class ScreenDrawer : public Drawer
|
|||
public:
|
||||
void Init(SamplerManager *samplerManager, ShaderManager *shaderManager)
|
||||
{
|
||||
if (!pipelineManager)
|
||||
pipelineManager = std::unique_ptr<PipelineManager>(new PipelineManager());
|
||||
Drawer::Init(samplerManager, shaderManager);
|
||||
if (!screenPipelineManager)
|
||||
screenPipelineManager = std::unique_ptr<PipelineManager>(new PipelineManager());
|
||||
screenPipelineManager->Init(shaderManager);
|
||||
Drawer::Init(samplerManager, screenPipelineManager.get());
|
||||
|
||||
if (descriptorSets.size() > GetContext()->GetSwapChainSize())
|
||||
descriptorSets.resize(GetContext()->GetSwapChainSize());
|
||||
|
|
@ -116,7 +117,7 @@ public:
|
|||
while (descriptorSets.size() < GetContext()->GetSwapChainSize())
|
||||
{
|
||||
descriptorSets.push_back(DescriptorSets());
|
||||
descriptorSets.back().Init(samplerManager, pipelineManager->GetPipelineLayout(), pipelineManager->GetPerFrameDSLayout(), pipelineManager->GetPerPolyDSLayout());
|
||||
descriptorSets.back().Init(samplerManager, screenPipelineManager->GetPipelineLayout(), screenPipelineManager->GetPerFrameDSLayout(), screenPipelineManager->GetPerPolyDSLayout());
|
||||
}
|
||||
}
|
||||
ScreenDrawer() = default;
|
||||
|
|
@ -158,19 +159,20 @@ private:
|
|||
|
||||
std::vector<DescriptorSets> descriptorSets;
|
||||
std::vector<std::unique_ptr<BufferData>> mainBuffers;
|
||||
std::unique_ptr<PipelineManager> screenPipelineManager;
|
||||
};
|
||||
|
||||
class TextureDrawer : public Drawer
|
||||
{
|
||||
public:
|
||||
void Init(SamplerManager *samplerManager, ShaderManager *shaderManager, VulkanAllocator *texAllocator)
|
||||
void Init(SamplerManager *samplerManager, VulkanAllocator *texAllocator, RttPipelineManager *pipelineManager, TextureCache *textureCache)
|
||||
{
|
||||
pipelineManager = std::unique_ptr<RttPipelineManager>(new RttPipelineManager());
|
||||
Drawer::Init(samplerManager, shaderManager);
|
||||
Drawer::Init(samplerManager, pipelineManager);
|
||||
|
||||
descriptorSets.Init(samplerManager, pipelineManager->GetPipelineLayout(), pipelineManager->GetPerFrameDSLayout(), pipelineManager->GetPerPolyDSLayout());
|
||||
fence = GetContext()->GetDevice()->createFenceUnique(vk::FenceCreateInfo());
|
||||
this->texAllocator = texAllocator;
|
||||
this->textureCache = textureCache;
|
||||
}
|
||||
void SetCommandPool(CommandPool *commandPool) { this->commandPool = commandPool; }
|
||||
|
||||
|
|
@ -179,10 +181,10 @@ public:
|
|||
TextureDrawer(TextureDrawer&& other) = default;
|
||||
TextureDrawer& operator=(const TextureDrawer& other) = delete;
|
||||
TextureDrawer& operator=(TextureDrawer&& other) = default;
|
||||
virtual void EndRenderPass() override;
|
||||
|
||||
protected:
|
||||
virtual vk::CommandBuffer BeginRenderPass() override;
|
||||
virtual void EndRenderPass() override;
|
||||
DescriptorSets& GetCurrentDescSet() override { return descriptorSets; }
|
||||
|
||||
virtual BufferData* GetMainBuffer(u32 size) override
|
||||
|
|
@ -216,4 +218,5 @@ private:
|
|||
std::unique_ptr<BufferData> mainBuffer;
|
||||
CommandPool *commandPool = nullptr;
|
||||
VulkanAllocator *texAllocator = nullptr;
|
||||
TextureCache *textureCache = nullptr;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
#include "pipeline.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
#include "rend/osd.h"
|
||||
|
||||
static const vk::CompareOp depthOps[] =
|
||||
{
|
||||
|
|
@ -379,9 +380,17 @@ void QuadPipeline::CreatePipeline()
|
|||
vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo;
|
||||
|
||||
// Color flags and blending
|
||||
vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState;
|
||||
pipelineColorBlendAttachmentState.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG
|
||||
| vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
|
||||
vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState(
|
||||
true, // blendEnable
|
||||
vk::BlendFactor::eConstantAlpha, // srcColorBlendFactor
|
||||
vk::BlendFactor::eOneMinusConstantAlpha, // dstColorBlendFactor
|
||||
vk::BlendOp::eAdd, // colorBlendOp
|
||||
vk::BlendFactor::eConstantAlpha, // srcAlphaBlendFactor
|
||||
vk::BlendFactor::eOneMinusConstantAlpha, // dstAlphaBlendFactor
|
||||
vk::BlendOp::eAdd, // alphaBlendOp
|
||||
vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG
|
||||
| vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA
|
||||
);
|
||||
vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo
|
||||
(
|
||||
vk::PipelineColorBlendStateCreateFlags(), // flags
|
||||
|
|
@ -392,8 +401,9 @@ void QuadPipeline::CreatePipeline()
|
|||
{ { 1.0f, 1.0f, 1.0f, 1.0f } } // blendConstants
|
||||
);
|
||||
|
||||
vk::DynamicState dynamicStates[2] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor };
|
||||
vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), 2, dynamicStates);
|
||||
vk::DynamicState dynamicStates[] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor, vk::DynamicState::eBlendConstants };
|
||||
vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), ARRAY_SIZE(dynamicStates),
|
||||
dynamicStates);
|
||||
|
||||
vk::PipelineShaderStageCreateInfo stages[] = {
|
||||
{ vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, shaderManager->GetQuadVertexShader(), "main" },
|
||||
|
|
@ -419,3 +429,88 @@ void QuadPipeline::CreatePipeline()
|
|||
|
||||
pipeline = GetContext()->GetDevice()->createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo);
|
||||
}
|
||||
|
||||
void OSDPipeline::CreatePipeline()
|
||||
{
|
||||
// Vertex input state
|
||||
static const vk::VertexInputBindingDescription vertexBindingDescriptions[] =
|
||||
{
|
||||
{ 0, sizeof(OSDVertex) },
|
||||
};
|
||||
static const vk::VertexInputAttributeDescription vertexInputAttributeDescriptions[] =
|
||||
{
|
||||
vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32Sfloat, offsetof(OSDVertex, x)), // pos
|
||||
vk::VertexInputAttributeDescription(1, 0, vk::Format::eR8G8B8A8Uint, offsetof(OSDVertex, r)), // color
|
||||
vk::VertexInputAttributeDescription(2, 0, vk::Format::eR32G32Sfloat, offsetof(OSDVertex, u)), // tex coord
|
||||
};
|
||||
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo(
|
||||
vk::PipelineVertexInputStateCreateFlags(),
|
||||
ARRAY_SIZE(vertexBindingDescriptions),
|
||||
vertexBindingDescriptions,
|
||||
ARRAY_SIZE(vertexInputAttributeDescriptions),
|
||||
vertexInputAttributeDescriptions);
|
||||
|
||||
// Input assembly state
|
||||
vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleStrip);
|
||||
|
||||
// Viewport and scissor states
|
||||
vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr);
|
||||
|
||||
// Rasterization and multisample states
|
||||
vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo;
|
||||
pipelineRasterizationStateCreateInfo.lineWidth = 1.0;
|
||||
vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo;
|
||||
|
||||
// Depth and stencil
|
||||
vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo;
|
||||
|
||||
// Color flags and blending
|
||||
vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState(
|
||||
true, // blendEnable
|
||||
vk::BlendFactor::eSrcAlpha, // srcColorBlendFactor
|
||||
vk::BlendFactor::eOneMinusSrcAlpha, // dstColorBlendFactor
|
||||
vk::BlendOp::eAdd, // colorBlendOp
|
||||
vk::BlendFactor::eSrcAlpha, // srcAlphaBlendFactor
|
||||
vk::BlendFactor::eOneMinusSrcAlpha, // dstAlphaBlendFactor
|
||||
vk::BlendOp::eAdd, // alphaBlendOp
|
||||
vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG
|
||||
| vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA
|
||||
);
|
||||
vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo
|
||||
(
|
||||
vk::PipelineColorBlendStateCreateFlags(), // flags
|
||||
false, // logicOpEnable
|
||||
vk::LogicOp::eNoOp, // logicOp
|
||||
1, // attachmentCount
|
||||
&pipelineColorBlendAttachmentState, // pAttachments
|
||||
{ { 1.0f, 1.0f, 1.0f, 1.0f } } // blendConstants
|
||||
);
|
||||
|
||||
vk::DynamicState dynamicStates[] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor };
|
||||
vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), ARRAY_SIZE(dynamicStates),
|
||||
dynamicStates);
|
||||
|
||||
vk::PipelineShaderStageCreateInfo stages[] = {
|
||||
{ vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, shaderManager->GetOSDVertexShader(), "main" },
|
||||
{ vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, shaderManager->GetOSDFragmentShader(), "main" },
|
||||
};
|
||||
vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo
|
||||
(
|
||||
vk::PipelineCreateFlags(), // flags
|
||||
2, // stageCount
|
||||
stages, // pStages
|
||||
&vertexInputStateCreateInfo, // pVertexInputState
|
||||
&pipelineInputAssemblyStateCreateInfo, // pInputAssemblyState
|
||||
nullptr, // pTessellationState
|
||||
&pipelineViewportStateCreateInfo, // pViewportState
|
||||
&pipelineRasterizationStateCreateInfo, // pRasterizationState
|
||||
&pipelineMultisampleStateCreateInfo, // pMultisampleState
|
||||
&pipelineDepthStencilStateCreateInfo, // pDepthStencilState
|
||||
&pipelineColorBlendStateCreateInfo, // pColorBlendState
|
||||
&pipelineDynamicStateCreateInfo, // pDynamicState
|
||||
*pipelineLayout, // layout
|
||||
renderPass // renderPass
|
||||
);
|
||||
|
||||
pipeline = GetContext()->GetDevice()->createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ public:
|
|||
descSetLayout = GetContext()->GetDevice()->createDescriptorSetLayoutUnique(
|
||||
vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), ARRAY_SIZE(bindings), bindings));
|
||||
pipelineLayout = GetContext()->GetDevice()->createPipelineLayoutUnique(
|
||||
vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descSetLayout.get(), 0, nullptr));
|
||||
vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descSetLayout.get()));
|
||||
}
|
||||
if (!sampler)
|
||||
{
|
||||
|
|
@ -360,5 +360,69 @@ private:
|
|||
vk::UniquePipelineLayout pipelineLayout;
|
||||
vk::UniqueDescriptorSetLayout descSetLayout;
|
||||
ShaderManager *shaderManager;
|
||||
SamplerManager *samplerManager;
|
||||
};
|
||||
|
||||
class OSDPipeline
|
||||
{
|
||||
public:
|
||||
void Init(ShaderManager *shaderManager, vk::ImageView imageView)
|
||||
{
|
||||
this->shaderManager = shaderManager;
|
||||
if (!pipelineLayout)
|
||||
{
|
||||
vk::DescriptorSetLayoutBinding bindings[] = {
|
||||
{ 0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment },// texture
|
||||
};
|
||||
descSetLayout = GetContext()->GetDevice()->createDescriptorSetLayoutUnique(
|
||||
vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), ARRAY_SIZE(bindings), bindings));
|
||||
pipelineLayout = GetContext()->GetDevice()->createPipelineLayoutUnique(
|
||||
vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descSetLayout.get()));
|
||||
}
|
||||
if (!sampler)
|
||||
{
|
||||
sampler = VulkanContext::Instance()->GetDevice()->createSamplerUnique(
|
||||
vk::SamplerCreateInfo(vk::SamplerCreateFlags(), vk::Filter::eLinear, vk::Filter::eLinear,
|
||||
vk::SamplerMipmapMode::eLinear, vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge,
|
||||
vk::SamplerAddressMode::eClampToEdge, 0.0f, false, 16.0f, false,
|
||||
vk::CompareOp::eNever, 0.0f, 0.0f, vk::BorderColor::eFloatOpaqueBlack));
|
||||
}
|
||||
if (GetContext()->GetRenderPass() != renderPass)
|
||||
{
|
||||
renderPass = GetContext()->GetRenderPass();
|
||||
pipeline.reset();
|
||||
}
|
||||
if (!descriptorSet)
|
||||
{
|
||||
descriptorSet = std::move(GetContext()->GetDevice()->allocateDescriptorSetsUnique(
|
||||
vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), 1, &descSetLayout.get())).front());
|
||||
}
|
||||
vk::DescriptorImageInfo imageInfo(*sampler, imageView, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
std::vector<vk::WriteDescriptorSet> writeDescriptorSets;
|
||||
writeDescriptorSets.push_back(vk::WriteDescriptorSet(*descriptorSet, 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr));
|
||||
GetContext()->GetDevice()->updateDescriptorSets(writeDescriptorSets, nullptr);
|
||||
}
|
||||
|
||||
vk::Pipeline GetPipeline()
|
||||
{
|
||||
if (!pipeline)
|
||||
CreatePipeline();
|
||||
return *pipeline;
|
||||
}
|
||||
|
||||
void BindDescriptorSets(vk::CommandBuffer cmdBuffer) const
|
||||
{
|
||||
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
VulkanContext *GetContext() const { return VulkanContext::Instance(); }
|
||||
void CreatePipeline();
|
||||
|
||||
vk::RenderPass renderPass;
|
||||
vk::UniquePipeline pipeline;
|
||||
vk::UniqueSampler sampler;
|
||||
vk::UniqueDescriptorSet descriptorSet;
|
||||
vk::UniquePipelineLayout pipelineLayout;
|
||||
vk::UniqueDescriptorSetLayout descSetLayout;
|
||||
ShaderManager *shaderManager;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -324,6 +324,41 @@ void main()
|
|||
}
|
||||
)";
|
||||
|
||||
static const char OSDVertexShaderSource[] = R"(
|
||||
#version 400
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
|
||||
layout (location = 0) in vec4 inPos;
|
||||
layout (location = 1) in uvec4 inColor;
|
||||
layout (location = 2) in vec2 inUV;
|
||||
layout (location = 0) out lowp vec4 outColor;
|
||||
layout (location = 1) out mediump vec2 outUV;
|
||||
|
||||
void main()
|
||||
{
|
||||
outColor = inColor / 255.0;
|
||||
outUV = inUV;
|
||||
gl_Position = inPos;
|
||||
}
|
||||
)";
|
||||
|
||||
static const char OSDFragmentShaderSource[] = R"(
|
||||
#version 400
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_ARB_shading_language_420pack : enable
|
||||
|
||||
layout (binding = 0) uniform sampler2D tex;
|
||||
layout (location = 0) in lowp vec4 inColor;
|
||||
layout (location = 1) in mediump vec2 inUV;
|
||||
layout (location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = inColor * texture(tex, inUV);
|
||||
}
|
||||
)";
|
||||
|
||||
static const TBuiltInResource DefaultTBuiltInResource = {
|
||||
/* .MaxLights = */ 32,
|
||||
/* .MaxClipPlanes = */ 6,
|
||||
|
|
@ -540,3 +575,13 @@ vk::UniqueShaderModule ShaderManager::compileQuadFragmentShader()
|
|||
{
|
||||
return createShaderModule(VulkanContext::Instance()->GetDevice(), vk::ShaderStageFlagBits::eFragment, QuadFragmentShaderSource);
|
||||
}
|
||||
|
||||
vk::UniqueShaderModule ShaderManager::compileOSDVertexShader()
|
||||
{
|
||||
return createShaderModule(VulkanContext::Instance()->GetDevice(), vk::ShaderStageFlagBits::eVertex, OSDVertexShaderSource);
|
||||
}
|
||||
|
||||
vk::UniqueShaderModule ShaderManager::compileOSDFragmentShader()
|
||||
{
|
||||
return createShaderModule(VulkanContext::Instance()->GetDevice(), vk::ShaderStageFlagBits::eFragment, OSDFragmentShaderSource);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,18 @@ public:
|
|||
quadFragmentShader = compileQuadFragmentShader();
|
||||
return *quadFragmentShader;
|
||||
}
|
||||
vk::ShaderModule GetOSDVertexShader()
|
||||
{
|
||||
if (!osdVertexShader)
|
||||
osdVertexShader = compileOSDVertexShader();
|
||||
return *osdVertexShader;
|
||||
}
|
||||
vk::ShaderModule GetOSDFragmentShader()
|
||||
{
|
||||
if (!osdFragmentShader)
|
||||
osdFragmentShader = compileOSDFragmentShader();
|
||||
return *osdFragmentShader;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
|
|
@ -128,6 +140,8 @@ private:
|
|||
vk::UniqueShaderModule compileModVolFragmentShader();
|
||||
vk::UniqueShaderModule compileQuadVertexShader();
|
||||
vk::UniqueShaderModule compileQuadFragmentShader();
|
||||
vk::UniqueShaderModule compileOSDVertexShader();
|
||||
vk::UniqueShaderModule compileOSDFragmentShader();
|
||||
|
||||
std::map<u32, vk::UniqueShaderModule> vertexShaders;
|
||||
std::map<u32, vk::UniqueShaderModule> fragmentShaders;
|
||||
|
|
@ -135,4 +149,6 @@ private:
|
|||
vk::UniqueShaderModule modVolShader;
|
||||
vk::UniqueShaderModule quadVertexShader;
|
||||
vk::UniqueShaderModule quadFragmentShader;
|
||||
vk::UniqueShaderModule osdVertexShader;
|
||||
vk::UniqueShaderModule osdFragmentShader;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@ void Texture::CreateImage(vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk:
|
|||
|
||||
void Texture::SetImage(u32 srcSize, void *srcData, bool isNew)
|
||||
{
|
||||
verify((bool)commandBuffer);
|
||||
commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit));
|
||||
|
||||
if (!isNew && !needsStaging)
|
||||
|
|
|
|||
|
|
@ -29,9 +29,6 @@ void setImageLayout(vk::CommandBuffer const& commandBuffer, vk::Image image, vk:
|
|||
|
||||
struct Texture : BaseTextureCacheData
|
||||
{
|
||||
Texture(vk::PhysicalDevice physicalDevice, vk::Device device, VulkanAllocator *allocator = nullptr)
|
||||
: physicalDevice(physicalDevice), device(device), format(vk::Format::eUndefined), allocator(allocator)
|
||||
{}
|
||||
~Texture() override
|
||||
{
|
||||
imageView.reset();
|
||||
|
|
@ -47,6 +44,10 @@ struct Texture : BaseTextureCacheData
|
|||
void SetCommandBuffer(vk::CommandBuffer commandBuffer) { this->commandBuffer = commandBuffer; }
|
||||
virtual bool Force32BitTexture(TextureType type) override { return !VulkanContext::Instance()->IsFormatSupported(type); }
|
||||
|
||||
void SetAllocator(VulkanAllocator *allocator) { this->allocator = allocator; }
|
||||
void SetPhysicalDevice(vk::PhysicalDevice physicalDevice) { this->physicalDevice = physicalDevice; }
|
||||
void SetDevice(vk::Device device) { this->device = device; }
|
||||
|
||||
private:
|
||||
void Init(u32 width, u32 height, vk::Format format);
|
||||
void SetImage(u32 size, void *data, bool isNew);
|
||||
|
|
@ -54,7 +55,7 @@ private:
|
|||
vk::MemoryPropertyFlags memoryProperties, vk::ImageAspectFlags aspectMask);
|
||||
void GenerateMipmaps();
|
||||
|
||||
vk::Format format;
|
||||
vk::Format format = vk::Format::eUndefined;
|
||||
vk::Extent2D extent;
|
||||
u32 mipmapLevels = 1;
|
||||
bool needsStaging = false;
|
||||
|
|
@ -67,7 +68,7 @@ private:
|
|||
|
||||
vk::PhysicalDevice physicalDevice;
|
||||
vk::Device device;
|
||||
VulkanAllocator *allocator;
|
||||
VulkanAllocator *allocator = nullptr;
|
||||
vk::DeviceMemory sharedDeviceMemory;
|
||||
u32 memoryType = 0;
|
||||
vk::DeviceSize memoryOffset = 0;
|
||||
|
|
@ -129,3 +130,7 @@ private:
|
|||
vk::PhysicalDevice physicalDevice;
|
||||
vk::Device device;
|
||||
};
|
||||
|
||||
class TextureCache : public BaseTextureCache<Texture>
|
||||
{
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
#include "commandpool.h"
|
||||
#include "drawer.h"
|
||||
#include "shaders.h"
|
||||
#include "../gui.h"
|
||||
#include "rend/gui.h"
|
||||
#include "rend/osd.h"
|
||||
|
||||
extern bool ProcessFrame(TA_context* ctx);
|
||||
|
||||
|
|
@ -41,14 +42,55 @@ public:
|
|||
|
||||
// FIXME this might be called after initial init
|
||||
texAllocator.SetChunkSize(16 * 1024 * 1024);
|
||||
while (textureDrawer.size() < 2)
|
||||
textureDrawer.emplace_back();
|
||||
textureDrawer[0].Init(&samplerManager, &shaderManager, &texAllocator);
|
||||
textureDrawer[0].SetCommandPool(&texCommandPool);
|
||||
textureDrawer[1].Init(&samplerManager, &shaderManager, &texAllocator);
|
||||
textureDrawer[1].SetCommandPool(&texCommandPool);
|
||||
rttPipelineManager.Init(&shaderManager);
|
||||
if (textureDrawer.size() > GetContext()->GetSwapChainSize())
|
||||
textureDrawer.resize(GetContext()->GetSwapChainSize());
|
||||
else
|
||||
{
|
||||
while (textureDrawer.size() < GetContext()->GetSwapChainSize())
|
||||
textureDrawer.emplace_back();
|
||||
}
|
||||
for (auto& drawer : textureDrawer)
|
||||
{
|
||||
drawer.Init(&samplerManager, &texAllocator, &rttPipelineManager, &textureCache);
|
||||
drawer.SetCommandPool(&texCommandPool);
|
||||
}
|
||||
|
||||
screenDrawer.Init(&samplerManager, &shaderManager);
|
||||
quadPipeline.Init(&shaderManager);
|
||||
#ifdef __ANDROID__
|
||||
if (!vjoyTexture)
|
||||
{
|
||||
int w, h;
|
||||
u8 *image_data = loadPNGData(get_readonly_data_path(DATA_PATH "buttons.png"), w, h);
|
||||
if (image_data == nullptr)
|
||||
{
|
||||
WARN_LOG(RENDERER, "Cannot load buttons.png image");
|
||||
}
|
||||
else
|
||||
{
|
||||
vjoyTexture = std::unique_ptr<Texture>(new Texture());
|
||||
vjoyTexture->tex_type = TextureType::_8888;
|
||||
vjoyTexture->tcw.full = 0;
|
||||
vjoyTexture->tsp.full = 0;
|
||||
vjoyTexture->SetAllocator(&texAllocator);
|
||||
vjoyTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
vjoyTexture->SetDevice(*GetContext()->GetDevice());
|
||||
vjoyTexture->SetCommandBuffer(texCommandPool.Allocate());
|
||||
vjoyTexture->UploadToGPU(OSD_TEX_W, OSD_TEX_H, image_data);
|
||||
vjoyTexture->SetCommandBuffer(nullptr);
|
||||
delete [] image_data;
|
||||
osdPipeline.Init(&shaderManager, vjoyTexture->GetImageView());
|
||||
}
|
||||
}
|
||||
if (!osdBuffer)
|
||||
{
|
||||
osdBuffer = std::unique_ptr<BufferData>(new BufferData(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice().get(),
|
||||
sizeof(OSDVertex) * VJOY_VISIBLE * 4,
|
||||
vk::BufferUsageFlagBits::eVertexBuffer, &texAllocator));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -58,13 +100,14 @@ public:
|
|||
texCommandPool.Init();
|
||||
screenDrawer.Init(&samplerManager, &shaderManager);
|
||||
quadPipeline.Init(&shaderManager);
|
||||
osdPipeline.Init(&shaderManager, vjoyTexture->GetImageView());
|
||||
}
|
||||
|
||||
void Term() override
|
||||
{
|
||||
DEBUG_LOG(RENDERER, "VulkanRenderer::Term");
|
||||
GetContext()->WaitIdle();
|
||||
killtex();
|
||||
textureCache.Clear();
|
||||
fogTexture = nullptr;
|
||||
texCommandPool.Term();
|
||||
shaderManager.Term();
|
||||
|
|
@ -86,10 +129,13 @@ public:
|
|||
std::unique_ptr<Texture>& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
|
||||
if (!curTexture)
|
||||
{
|
||||
curTexture = std::unique_ptr<Texture>(new Texture(GetContext()->GetPhysicalDevice(), *GetContext()->GetDevice(), &texAllocator));
|
||||
curTexture = std::unique_ptr<Texture>(new Texture());
|
||||
curTexture->tex_type = TextureType::_8888;
|
||||
curTexture->tcw.full = 0;
|
||||
curTexture->tsp.full = 0;
|
||||
curTexture->SetAllocator(&texAllocator);
|
||||
curTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
curTexture->SetDevice(*GetContext()->GetDevice());
|
||||
}
|
||||
curTexture->SetCommandBuffer(texCommandPool.Allocate());
|
||||
curTexture->UploadToGPU(width, height, (u8*)pb.data());
|
||||
|
|
@ -117,6 +163,8 @@ public:
|
|||
quadPipeline.SetTexture(curTexture.get());
|
||||
quadPipeline.BindDescriptorSets(cmdBuffer);
|
||||
|
||||
float blendConstants[4] = { 1.0, 1.0, 1.0, 1.0 };
|
||||
cmdBuffer.setBlendConstants(blendConstants);
|
||||
// FIXME scaling, stretching...
|
||||
vk::Viewport viewport(ds2s_offs_x, 0.f, screen_width - ds2s_offs_x * 2, (float)screen_height);
|
||||
cmdBuffer.setViewport(0, 1, &viewport);
|
||||
|
|
@ -138,7 +186,19 @@ public:
|
|||
return RenderFramebuffer();
|
||||
}
|
||||
|
||||
bool result = ProcessFrame(ctx);
|
||||
ctx->rend_inuse.Lock();
|
||||
|
||||
if (KillTex)
|
||||
textureCache.Clear();
|
||||
|
||||
bool result = ta_parse_vdrc(ctx);
|
||||
|
||||
textureCache.CollectCleanup();
|
||||
|
||||
if (ctx->rend.Overrun)
|
||||
WARN_LOG(PVR, "ERROR: TA context overrun");
|
||||
|
||||
result = result && !ctx->rend.Overrun;
|
||||
|
||||
if (result)
|
||||
CheckFogTexture();
|
||||
|
|
@ -151,6 +211,51 @@ public:
|
|||
|
||||
void DrawOSD(bool clear_screen) override
|
||||
{
|
||||
if (!vjoyTexture)
|
||||
return;
|
||||
if (clear_screen)
|
||||
{
|
||||
GetContext()->NewFrame();
|
||||
GetContext()->BeginRenderPass();
|
||||
}
|
||||
const float screen_stretching = settings.rend.ScreenStretching / 100.f;
|
||||
float dc2s_scale_h, ds2s_offs_x;
|
||||
if (settings.rend.Rotate90)
|
||||
{
|
||||
dc2s_scale_h = screen_height / 640.0f;
|
||||
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0f * screen_stretching) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
dc2s_scale_h = screen_height / 480.0f;
|
||||
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0f * screen_stretching) / 2;
|
||||
}
|
||||
std::vector<OSDVertex> osdVertices = GetOSDVertices();
|
||||
const float x1 = 2.0f / (screen_width / dc2s_scale_h /* FIXME * scale_x */) * screen_stretching;
|
||||
const float y1 = 2.0f / 480 /* FIXME dc_height */;
|
||||
const float x2 = 1 - 2 * ds2s_offs_x / screen_width;
|
||||
const float y2 = 1;
|
||||
for (OSDVertex& vtx : osdVertices)
|
||||
{
|
||||
vtx.x = vtx.x * x1 - x2;
|
||||
vtx.y = vtx.y * y1 - y2;
|
||||
}
|
||||
|
||||
const vk::CommandBuffer cmdBuffer = GetContext()->GetCurrentCommandBuffer();
|
||||
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, osdPipeline.GetPipeline());
|
||||
|
||||
osdPipeline.BindDescriptorSets(cmdBuffer);
|
||||
const vk::Viewport viewport(0, 0, (float)screen_width, (float)screen_height, 0, 1.f);
|
||||
cmdBuffer.setViewport(0, 1, &viewport);
|
||||
const vk::Rect2D scissor({ 0, 0 }, { (u32)screen_width, (u32)screen_height });
|
||||
cmdBuffer.setScissor(0, 1, &scissor);
|
||||
osdBuffer->upload(*GetContext()->GetDevice(), osdVertices.size() * sizeof(OSDVertex), osdVertices.data());
|
||||
const vk::DeviceSize zero = 0;
|
||||
cmdBuffer.bindVertexBuffers(0, 1, &osdBuffer->buffer.get(), &zero);
|
||||
for (int i = 0; i < osdVertices.size(); i += 4)
|
||||
cmdBuffer.draw(4, 1, i, 0);
|
||||
if (clear_screen)
|
||||
GetContext()->EndFrame();
|
||||
}
|
||||
|
||||
bool Render() override
|
||||
|
|
@ -158,14 +263,18 @@ public:
|
|||
if (pvrrc.isRenderFramebuffer)
|
||||
return true;
|
||||
|
||||
Drawer *drawer;
|
||||
if (pvrrc.isRTT)
|
||||
{
|
||||
textureDrawer[curTextureDrawer].Draw(fogTexture.get());
|
||||
curTextureDrawer ^= 1;
|
||||
return false;
|
||||
}
|
||||
drawer = &textureDrawer[GetContext()->GetCurrentImageIndex()];
|
||||
else
|
||||
return screenDrawer.Draw(fogTexture.get());
|
||||
drawer = &screenDrawer;
|
||||
|
||||
drawer->Draw(fogTexture.get());
|
||||
if (!pvrrc.isRTT)
|
||||
DrawOSD(false);
|
||||
drawer->EndRenderPass();
|
||||
|
||||
return !pvrrc.isRTT;
|
||||
}
|
||||
|
||||
void Present() override
|
||||
|
|
@ -175,12 +284,15 @@ public:
|
|||
|
||||
virtual u64 GetTexture(TSP tsp, TCW tcw) override
|
||||
{
|
||||
Texture* tf = static_cast<Texture*>(getTextureCacheData(tsp, tcw, [this](){
|
||||
return (BaseTextureCacheData *)new Texture(VulkanContext::Instance()->GetPhysicalDevice(), *VulkanContext::Instance()->GetDevice(), &this->texAllocator);
|
||||
}));
|
||||
Texture* tf = textureCache.getTextureCacheData(tsp, tcw);
|
||||
|
||||
if (tf->IsNew())
|
||||
{
|
||||
tf->Create();
|
||||
tf->SetAllocator(&texAllocator);
|
||||
tf->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
tf->SetDevice(*GetContext()->GetDevice());
|
||||
}
|
||||
|
||||
//update if needed
|
||||
if (tf->NeedsUpdate())
|
||||
|
|
@ -202,7 +314,10 @@ private:
|
|||
{
|
||||
if (!fogTexture)
|
||||
{
|
||||
fogTexture = std::unique_ptr<Texture>(new Texture(GetContext()->GetPhysicalDevice(), *GetContext()->GetDevice()));
|
||||
fogTexture = std::unique_ptr<Texture>(new Texture());
|
||||
fogTexture->SetAllocator(&texAllocator);
|
||||
fogTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
|
||||
fogTexture->SetDevice(*GetContext()->GetDevice());
|
||||
fogTexture->tex_type = TextureType::_8;
|
||||
fog_needs_update = true;
|
||||
}
|
||||
|
|
@ -224,11 +339,15 @@ private:
|
|||
SamplerManager samplerManager;
|
||||
ShaderManager shaderManager;
|
||||
ScreenDrawer screenDrawer;
|
||||
std::vector<TextureDrawer> textureDrawer; // FIXME should be a singleton
|
||||
int curTextureDrawer = 0;
|
||||
RttPipelineManager rttPipelineManager;
|
||||
std::vector<TextureDrawer> textureDrawer;
|
||||
VulkanAllocator texAllocator;
|
||||
std::vector<std::unique_ptr<Texture>> framebufferTextures;
|
||||
QuadPipeline quadPipeline;
|
||||
OSDPipeline osdPipeline;
|
||||
std::unique_ptr<Texture> vjoyTexture;
|
||||
std::unique_ptr<BufferData> osdBuffer;
|
||||
TextureCache textureCache;
|
||||
};
|
||||
|
||||
Renderer* rend_Vulkan()
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@
|
|||
AE8C274221122E2500D4D8F4 /* License.txt in Resources */ = {isa = PBXBuildFile; fileRef = AE8C273C21122E2500D4D8F4 /* License.txt */; };
|
||||
AE8C274321122E2500D4D8F4 /* xbrz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE8C273D21122E2500D4D8F4 /* xbrz.cpp */; };
|
||||
AE90679B235B6F6400CE473C /* gl_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE90679A235B6F6400CE473C /* gl_context.cpp */; };
|
||||
AE90679D235DF80400CE473C /* osd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE90679C235DF80400CE473C /* osd.cpp */; };
|
||||
AED73BAE22FC0E9600ECDB64 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = AED73BAD22FC0E9600ECDB64 /* README.md */; };
|
||||
AED73DC42303E19200ECDB64 /* sdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AED73DC02303E19100ECDB64 /* sdl.cpp */; };
|
||||
AED73DC72303E57C00ECDB64 /* libSDL2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AED73DC62303E57C00ECDB64 /* libSDL2.a */; };
|
||||
|
|
@ -850,6 +851,7 @@
|
|||
AE8C273F21122E2500D4D8F4 /* xbrz_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xbrz_config.h; sourceTree = "<group>"; };
|
||||
AE8C274021122E2500D4D8F4 /* xbrz_tools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xbrz_tools.h; sourceTree = "<group>"; };
|
||||
AE90679A235B6F6400CE473C /* gl_context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gl_context.cpp; sourceTree = "<group>"; };
|
||||
AE90679C235DF80400CE473C /* osd.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = osd.cpp; sourceTree = "<group>"; };
|
||||
AED73BAD22FC0E9600ECDB64 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../../core/README.md; sourceTree = "<group>"; };
|
||||
AED73DC02303E19100ECDB64 /* sdl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sdl.cpp; sourceTree = "<group>"; };
|
||||
AED73DC12303E19100ECDB64 /* sdl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sdl.h; sourceTree = "<group>"; };
|
||||
|
|
@ -1858,6 +1860,7 @@
|
|||
AEE62769220D7B5500EC7E89 /* gui.h */,
|
||||
AEE6279222247C0A00EC7E89 /* gui_util.cpp */,
|
||||
AEE6279322247C0A00EC7E89 /* gui_util.h */,
|
||||
AE90679C235DF80400CE473C /* osd.cpp */,
|
||||
84B7BEA21B72720200F9733F /* rend.h */,
|
||||
AED73EAD2348E49900ECDB64 /* sorter.cpp */,
|
||||
AED73EBD2348E49900ECDB64 /* sorter.h */,
|
||||
|
|
@ -2826,6 +2829,7 @@
|
|||
84B7BF201B72720200F9733F /* uncompr.c in Sources */,
|
||||
AE649C2A218C553A00EF4A81 /* LzFind.c in Sources */,
|
||||
84B7BF2A1B72720200F9733F /* arm7.cpp in Sources */,
|
||||
AE90679D235DF80400CE473C /* osd.cpp in Sources */,
|
||||
84B7BF0D1B72720200F9733F /* zip_source_zip.c in Sources */,
|
||||
84B7BEF51B72720200F9733F /* zip_fopen.c in Sources */,
|
||||
84B7BF551B72720200F9733F /* sh4_mem.cpp in Sources */,
|
||||
|
|
|
|||
Loading…
Reference in New Issue