diff --git a/src/Application.cpp b/src/Application.cpp index bf59b51..7833723 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -78,7 +78,6 @@ bool Application::init(const char* title, int width, int height) kAllocatorInited, kSdlInited, kWindowInited, - kRendererInited, kAudioDeviceInited, kFifoInited, kAudioInited, @@ -117,8 +116,16 @@ bool Application::init(const char* title, int width, int height) inited = kSdlInited; // Setup window + if (SDL_GL_LoadLibrary(NULL) != 0) + { + _logger.printf(RETRO_LOG_ERROR, "SDL_GL_LoadLibrary: %s", SDL_GetError()); + goto error; + } + + SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); _window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); @@ -128,55 +135,24 @@ bool Application::init(const char* title, int width, int height) goto error; } - int major, minor; - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); - _logger.printf(RETRO_LOG_ERROR, "Got OpenGL %d.%d", major, minor); - - inited = kWindowInited; - { - int numdrivers = SDL_GetNumRenderDrivers(); - _logger.printf(RETRO_LOG_INFO, "Render driver count: %d", numdrivers); - - for (int i = 0; i < numdrivers; i++) + SDL_GLContext context = SDL_GL_CreateContext(_window); + + if (SDL_GL_MakeCurrent(_window, context) != 0) { - SDL_RendererInfo drinfo; - SDL_GetRenderDriverInfo(i, &drinfo); - - _logger.printf(RETRO_LOG_INFO, "Driver %d name: %s", i, drinfo.name); - - if (drinfo.flags & SDL_RENDERER_SOFTWARE) - { - _logger.printf(RETRO_LOG_INFO, " the renderer is a software fallback"); - } - - if (drinfo.flags & SDL_RENDERER_ACCELERATED) - { - _logger.printf(RETRO_LOG_INFO, " the renderer uses hardware acceleration"); - } - - if (drinfo.flags & SDL_RENDERER_PRESENTVSYNC) - { - _logger.printf(RETRO_LOG_INFO, " present is synchronized with the refresh rate"); - } - - if (drinfo.flags & SDL_RENDERER_TARGETTEXTURE) - { - _logger.printf(RETRO_LOG_INFO, " the renderer supports rendering to texture"); - } + _logger.printf(RETRO_LOG_ERROR, "SDL_GL_MakeCurrent: %s", SDL_GetError()); + goto error; } } - _renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + SDL_GL_SetSwapInterval(1); - if (_renderer == NULL) - { - _logger.printf(RETRO_LOG_ERROR, "SDL_CreateRenderer: %s", SDL_GetError()); - goto error; - } + int major, minor; + SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); + SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); + _logger.printf(RETRO_LOG_ERROR, "Got OpenGL %d.%d", major, minor); - inited = kRendererInited; + inited = kWindowInited; // Init audio SDL_AudioSpec want; @@ -238,7 +214,7 @@ bool Application::init(const char* title, int width, int height) inited = kKeyBindsInited; - if (!_video.init(&_logger, &_config, _renderer)) + if (!_video.init(&_logger, &_config)) { goto error; } @@ -285,7 +261,6 @@ bool Application::init(const char* title, int width, int height) case kAudioInited: _audio.destroy(); case kFifoInited: _fifo.destroy(); case kAudioDeviceInited: SDL_CloseAudioDevice(_audioDev); - case kRendererInited: SDL_DestroyRenderer(_renderer); case kWindowInited: SDL_DestroyWindow(_window); case kSdlInited: SDL_Quit(); case kAllocatorInited: _allocator.destroy(); @@ -327,6 +302,10 @@ void Application::run() case SDL_KEYDOWN: handle(&event.key); break; + + case SDL_WINDOWEVENT: + handle(&event.window); + break; } } @@ -370,9 +349,7 @@ void Application::run() RA_DoAchievementsFrame(); } - SDL_RenderClear(_renderer); _video.draw(); - SDL_RenderPresent(_renderer); RA_HandleHTTPResults(); @@ -435,7 +412,6 @@ void Application::destroy() _fifo.destroy(); SDL_CloseAudioDevice(_audioDev); - SDL_DestroyRenderer(_renderer); SDL_DestroyWindow(_window); SDL_Quit(); @@ -1560,6 +1536,14 @@ void Application::handle(const SDL_SysWMEvent* syswm) } } +void Application::handle(const SDL_WindowEvent* window) +{ + if (window->event == SDL_WINDOWEVENT_SIZE_CHANGED) + { + _video.windowResized(window->data1, window->data2); + } +} + void Application::handle(const SDL_KeyboardEvent* key) { unsigned extra; diff --git a/src/Application.h b/src/Application.h index 6992bd2..5b8c6e1 100644 --- a/src/Application.h +++ b/src/Application.h @@ -100,6 +100,7 @@ class Application void loadRecentList(); std::string serializeRecentList(); void handle(const SDL_SysWMEvent* syswm); + void handle(const SDL_WindowEvent* window); void handle(const SDL_KeyboardEvent* key); Fsm _fsm; @@ -109,7 +110,6 @@ class Application System _system; SDL_Window* _window; - SDL_Renderer* _renderer; SDL_AudioSpec _audioSpec; SDL_AudioDeviceID _audioDev; diff --git a/src/Emulator.h b/src/Emulator.h index b033cc8..1119e13 100644 --- a/src/Emulator.h +++ b/src/Emulator.h @@ -62,7 +62,7 @@ enum class System kPlayStation1 = PlayStation, kNeoGeoPocket = NeoGeo, kVirtualBoy = VirtualBoy, - kGameGear = Xbox360, //GameGear, + kGameGear = GameGear, kArcade = Arcade, kNintendo64 = N64 }; diff --git a/src/Gl.cpp b/src/Gl.cpp index 2e96ffb..b2cef9c 100644 --- a/src/Gl.cpp +++ b/src/Gl.cpp @@ -1,125 +1,489 @@ #include "Gl.h" #include +#include -Gl::Gl(libretro::LoggerComponent* logger): _logger(logger), _ok(true) +bool Gl::init(libretro::LoggerComponent* logger) { - glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)SDL_GL_GetProcAddress("glGenFramebuffers"); - glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)SDL_GL_GetProcAddress("glBindRenderbuffer"); - glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)SDL_GL_GetProcAddress("glBindFramebuffer"); - glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)SDL_GL_GetProcAddress("glFramebufferTexture2D"); - glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)SDL_GL_GetProcAddress("glRenderbufferStorage"); - glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)SDL_GL_GetProcAddress("glFramebufferRenderbuffer"); -} + _logger = logger; + _ok = true; + + _glGenBuffers = (PFNGLGENBUFFERSPROC)getProcAddress("glGenBuffers"); + _glBindBuffer = (PFNGLBINDBUFFERPROC)getProcAddress("glBindBuffer"); + _glBufferData = (PFNGLBUFFERDATAPROC)getProcAddress("glBufferData"); + _glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)getProcAddress("glVertexAttribPointer"); + _glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)getProcAddress("glEnableVertexAttribArray"); -void Gl::genFramebuffers(GLsizei n, GLuint* ids) -{ - glGenFramebuffers(n, ids); - check(); + _glCreateShader = (PFNGLCREATESHADERPROC)getProcAddress("glCreateShader"); + _glDeleteShader = (PFNGLDELETESHADERPROC)getProcAddress("glDeleteShader"); + _glShaderSource = (PFNGLSHADERSOURCEPROC)getProcAddress("glShaderSource"); + _glCompileShader = (PFNGLCOMPILESHADERPROC)getProcAddress("glCompileShader"); + _glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)getProcAddress("glGetShaderInfoLog"); + + _glCreateProgram = (PFNGLCREATEPROGRAMPROC)getProcAddress("glCreateProgram"); + _glDeleteProgram = (PFNGLDELETEPROGRAMPROC)getProcAddress("glDeleteProgram"); + _glAttachShader = (PFNGLATTACHSHADERPROC)getProcAddress("glAttachShader"); + _glLinkProgram = (PFNGLLINKPROGRAMPROC)getProcAddress("glLinkProgram"); + _glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)getProcAddress("glValidateProgram"); + _glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)getProcAddress("glGetProgramInfoLog"); + _glUseProgram = (PFNGLUSEPROGRAMPROC)getProcAddress("glUseProgram"); + _glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)getProcAddress("glGetAttribLocation"); + _glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)getProcAddress("glGetUniformLocation"); + _glUniform2f = (PFNGLUNIFORM2FPROC)getProcAddress("glUniform2f"); + + _glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)getProcAddress("glGenFramebuffers"); + _glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)getProcAddress("glDeleteFramebuffers"); + _glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)getProcAddress("glBindRenderbuffer"); + _glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)getProcAddress("glBindFramebuffer"); + _glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)getProcAddress("glFramebufferTexture2D"); + _glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)getProcAddress("glRenderbufferStorage"); + _glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)getProcAddress("glFramebufferRenderbuffer"); + _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)getProcAddress("glDrawBuffers"); + + _glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)getProcAddress("glGenRenderbuffers"); + _glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)getProcAddress("glDeleteRenderbuffers"); + + return _ok; } void Gl::genTextures(GLsizei n, GLuint* textures) { + if (!_ok) return; glGenTextures(n, textures); - check(); + check(__FUNCTION__); } -void Gl::bindRenderbuffer(GLenum target, GLuint renderbuffer) +void Gl::deleteTextures(GLsizei n, const GLuint* textures) { - glBindRenderbuffer(target, renderbuffer); - check(); + if (!_ok) return; + glDeleteTextures(n, textures); + check(__FUNCTION__); } -void Gl::bindFramebuffer(GLenum target, GLuint framebuffer) +void Gl::bindTexture(GLenum target, GLuint texture) { - glBindFramebuffer(target, framebuffer); - check(); + if (!_ok) return; + glBindTexture(target, texture); + check(__FUNCTION__); } -void Gl::bindTexture(GLenum target, GLuint texture) +void Gl::texParameteri(GLenum target, GLenum pname, GLint param) { - glBindTexture(target, texture); - check(); + if (!_ok) return; + glTexParameteri(target, pname, param); + check(__FUNCTION__); } void Gl::texImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* data) { + if (!_ok) return; glTexImage2D(target, level, internalFormat, width, height, border, format, type, data); - check(); + check(__FUNCTION__); +} +void Gl::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) +{ + if (!_ok) return; + glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); + check(__FUNCTION__); } -void Gl::texParameteri(GLenum target, GLenum pname, GLint param) + +void Gl::genBuffers(GLsizei n, GLuint* buffers) { - glTexParameteri(target, pname, param); - check(); + if (!_ok) return; + _glGenBuffers(n, buffers); + check(__FUNCTION__); +} + +void Gl::deleteBuffers(GLsizei n, const GLuint* buffers) +{ + if (!_ok) return; + _glDeleteBuffers(n, buffers); + check(__FUNCTION__); +} + +void Gl::bindBuffer(GLenum target, GLuint buffer) +{ + if (!_ok) return; + _glBindBuffer(target, buffer); + check(__FUNCTION__); +} + +void Gl::bufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +{ + if (!_ok) return; + _glBufferData(target, size, data, usage); + check(__FUNCTION__); +} + +void Gl::vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer) +{ + if (!_ok) return; + _glVertexAttribPointer(index, size, type, normalized, stride, pointer); + check(__FUNCTION__); +} + +void Gl::enableVertexAttribArray(GLuint index) +{ + if (!_ok) return; + _glEnableVertexAttribArray(index); + check(__FUNCTION__); +} + +GLuint Gl::createShader(GLenum shaderType) +{ + if (!_ok) return 0; + GLuint shader = _glCreateShader(shaderType); + check(__FUNCTION__, shader != 0); + return shader; +} + +void Gl::deleteShader(GLuint shader) +{ + if (!_ok) return; + _glDeleteShader(shader); + check(__FUNCTION__); +} + +void Gl::shaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) +{ + if (!_ok) return; + _glShaderSource(shader, count, string, length); + check(__FUNCTION__); +} + +void Gl::compileShader(GLuint shader) +{ + if (!_ok) return; + _glCompileShader(shader); + check(__FUNCTION__); +} + +void Gl::getShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + if (!_ok) return; + getShaderiv(shader, pname, params); + check(__FUNCTION__); +} + +void Gl::getShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog) +{ + if (!_ok) return; + _glGetShaderInfoLog(shader, maxLength, length, infoLog); + check(__FUNCTION__); +} + +GLuint Gl::createShader(GLenum shaderType, const char* source) +{ + if (!_ok) return 0; + + GLuint shader = createShader(shaderType); + shaderSource(shader, 1, &source, NULL); + compileShader(shader); + + GLint status; + getShaderiv(shader, GL_COMPILE_STATUS, &status); + + if (status == GL_FALSE) + { + char buffer[4096]; + getShaderInfoLog(shader, sizeof(buffer), NULL, buffer); + _logger->printf(RETRO_LOG_ERROR, "Error in shader: %s", buffer); + deleteShader(shader); + return 0; + } + + if (!_ok) + { + deleteShader(shader); + return 0; + } + + return shader; +} + +GLuint Gl::createProgram() +{ + if (!_ok) return 0; + GLuint program = _glCreateProgram(); + check(__FUNCTION__, program != 0); + return program; +} + +void Gl::deleteProgram(GLuint program) +{ + if (!_ok) return; + _glDeleteProgram(program); + check(__FUNCTION__); +} + +void Gl::attachShader(GLuint program, GLuint shader) +{ + if (!_ok) return; + _glAttachShader(program, shader); + check(__FUNCTION__); +} + +void Gl::linkProgram(GLuint program) +{ + if (!_ok) return; + _glLinkProgram(program); + check(__FUNCTION__); +} + +void Gl::validateProgram(GLuint program) +{ + if (!_ok) return; + _glValidateProgram(program); + check(__FUNCTION__); +} + +void Gl::getProgramiv(GLuint program, GLenum pname, GLint* params) +{ + if (!_ok) return; + getProgramiv(program, pname, params); + check(__FUNCTION__); +} + +void Gl::getProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei* length, GLchar* infoLog) +{ + if (!_ok) return; + _glGetProgramInfoLog(program, maxLength, length, infoLog); + check(__FUNCTION__); +} + +void Gl::useProgram(GLuint program) +{ + if (!_ok) return; + _glUseProgram(program); + check(__FUNCTION__); +} + +GLint Gl::getAttribLocation(GLuint program, const GLchar* name) +{ + if (!_ok) return -1; + GLint location = _glGetAttribLocation(program, name); + check(__FUNCTION__, location != -1); + return location; +} + +GLint Gl::getUniformLocation(GLuint program, const GLchar* name) +{ + if (!_ok) return -1; + GLint location = _glGetUniformLocation(program, name); + check(__FUNCTION__, location != -1); + return location; +} + +void Gl::uniform2f(GLint location, GLfloat v0, GLfloat v1) +{ + if (!_ok) return; + _glUniform2f(location, v0, v1); + check(__FUNCTION__); +} + +GLuint Gl::createProgram(const char* vertexShader, const char* fragmentShader) +{ + if (!_ok) return 0; + + GLuint vs = createShader(GL_VERTEX_SHADER, vertexShader); + GLuint fs = createShader(GL_FRAGMENT_SHADER, fragmentShader); + GLuint program = createProgram(); + + attachShader(program, vs); + attachShader(program, fs); + linkProgram(program); + + deleteShader(vs); + deleteShader(fs); + + validateProgram(program); + + GLint status; + getProgramiv(program, GL_LINK_STATUS, &status); + + if (status == GL_FALSE) + { + char buffer[4096]; + getProgramInfoLog(program, sizeof(buffer), NULL, buffer); + _logger->printf(RETRO_LOG_ERROR, "Error in shader program: %s", buffer); + deleteProgram(program); + return 0; + } + + if (!_ok) + { + deleteProgram(program); + return 0; + } + + return program; +} + +void Gl::genFramebuffers(GLsizei n, GLuint* ids) +{ + if (!_ok) return; + _glGenFramebuffers(n, ids); + check(__FUNCTION__); +} + +void Gl::deleteFramebuffers(GLsizei n, GLuint* ids) +{ + if (!_ok) return; + _glDeleteFramebuffers(n, ids); + check(__FUNCTION__); +} + +void Gl::bindFramebuffer(GLenum target, GLuint framebuffer) +{ + if (!_ok) return; + _glBindFramebuffer(target, framebuffer); + check(__FUNCTION__); } void Gl::framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { - glFramebufferTexture2D(target, attachment, textarget, texture, level); - check(); + if (!_ok) return; + _glFramebufferTexture2D(target, attachment, textarget, texture, level); + check(__FUNCTION__); +} + +void Gl::framebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ + if (!_ok) return; + _glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); + check(__FUNCTION__); +} + +void Gl::drawBuffers(GLsizei n, const GLenum* bufs) +{ + if (!_ok) return; + _glDrawBuffers(n, bufs); + check(__FUNCTION__); +} + +void Gl::genRenderbuffers(GLsizei n, GLuint* renderbuffers) +{ + if (!_ok) return; + _glGenRenderbuffers(n, renderbuffers); + check(__FUNCTION__); +} + +void Gl::deleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +{ + if (!_ok) return; + _glDeleteRenderbuffers(n, renderbuffers); + check(__FUNCTION__); +} + +void Gl::bindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + if (!_ok) return; + _glBindRenderbuffer(target, renderbuffer); + check(__FUNCTION__); } void Gl::renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { - glRenderbufferStorage(target, internalformat, width, height); - check(); + if (!_ok) return; + _glRenderbufferStorage(target, internalformat, width, height); + check(__FUNCTION__); } -void Gl::framebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +void Gl::clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); - check(); + if (!_ok) return; + glClearColor(red, green, blue, alpha); + check(__FUNCTION__); +} + +void Gl::clear(GLbitfield mask) +{ + if (!_ok) return; + glClear(mask); + check(__FUNCTION__); } void Gl::enable(GLenum cap) { + if (!_ok) return; glEnable(cap); - check(); + check(__FUNCTION__); } void Gl::disable(GLenum cap) { + if (!_ok) return; glDisable(cap); - check(); + check(__FUNCTION__); } void Gl::blendFunc(GLenum sfactor, GLenum dfactor) { + if (!_ok) return; glBlendFunc(sfactor, dfactor); - check(); + check(__FUNCTION__); +} + +void Gl::drawArrays(GLenum mode, GLint first, GLsizei count) +{ + if (!_ok) return; + glDrawArrays(mode, first, count); + check(__FUNCTION__); +} + +void Gl::reset() +{ + check(__FUNCTION__); + _ok = true; +} + +void* Gl::getProcAddress(const char* symbol) +{ + if (!_ok) return NULL; + + void* address = SDL_GL_GetProcAddress(symbol); + + if (address == NULL) + { + _ok = false; + _logger->printf(RETRO_LOG_ERROR, "Error in %s: symbol %s not found", __FUNCTION__, symbol); + } + + return address; } -void Gl::check() +void Gl::check(const char* function, bool ok) { GLenum err = glGetError(); - if (err != GL_NO_ERROR) + if (err != GL_NO_ERROR || !ok) { _ok = false; + _logger->printf(RETRO_LOG_ERROR, "Error in %s:", function); do { switch (err) { case GL_INVALID_OPERATION: - _logger->printf(RETRO_LOG_ERROR, "INVALID_OPERATION"); + _logger->printf(RETRO_LOG_ERROR, " INVALID_OPERATION"); break; case GL_INVALID_ENUM: - _logger->printf(RETRO_LOG_ERROR, "INVALID_ENUM"); + _logger->printf(RETRO_LOG_ERROR, " INVALID_ENUM"); break; case GL_INVALID_VALUE: - _logger->printf(RETRO_LOG_ERROR, "INVALID_VALUE"); + _logger->printf(RETRO_LOG_ERROR, " INVALID_VALUE"); break; case GL_OUT_OF_MEMORY: - _logger->printf(RETRO_LOG_ERROR, "OUT_OF_MEMORY"); + _logger->printf(RETRO_LOG_ERROR, " OUT_OF_MEMORY"); break; case GL_INVALID_FRAMEBUFFER_OPERATION: - _logger->printf(RETRO_LOG_ERROR, "INVALID_FRAMEBUFFER_OPERATION"); + _logger->printf(RETRO_LOG_ERROR, " INVALID_FRAMEBUFFER_OPERATION"); break; } diff --git a/src/Gl.h b/src/Gl.h index 40fc39a..9c069f8 100644 --- a/src/Gl.h +++ b/src/Gl.h @@ -7,34 +7,107 @@ class Gl { public: - Gl(libretro::LoggerComponent* logger); + Gl() {} + + bool init(libretro::LoggerComponent* logger); - void genFramebuffers(GLsizei n, GLuint* ids); void genTextures(GLsizei n, GLuint* textures); - void bindRenderbuffer(GLenum target, GLuint renderbuffer); - void bindFramebuffer(GLenum target, GLuint framebuffer); + void deleteTextures(GLsizei n, const GLuint* textures); void bindTexture(GLenum target, GLuint texture); - void texImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* data); void texParameteri(GLenum target, GLenum pname, GLint param); + void texImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* data); + void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); + + void genBuffers(GLsizei n, GLuint* buffers); + void deleteBuffers(GLsizei n, const GLuint* buffers); + void bindBuffer(GLenum target, GLuint buffer); + void bufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); + void vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer); + void enableVertexAttribArray(GLuint index); + + GLuint createShader(GLenum shaderType); + void deleteShader(GLuint shader); + void shaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); + void compileShader(GLuint shader); + void getShaderiv(GLuint shader, GLenum pname, GLint* params); + void getShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog); + GLuint createShader(GLenum shaderType, const char* source); // helper + + GLuint createProgram(); + void deleteProgram(GLuint program); + void attachShader(GLuint program, GLuint shader); + void linkProgram(GLuint program); + void validateProgram(GLuint program); + void getProgramiv(GLuint program, GLenum pname, GLint* params); + void getProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei* length, GLchar* infoLog); + void useProgram(GLuint program); + GLint getAttribLocation(GLuint program, const GLchar* name); + GLint getUniformLocation(GLuint program, const GLchar* name); + void uniform2f(GLint location, GLfloat v0, GLfloat v1); + GLuint createProgram(const char* vertexShader, const char* fragmentShader); // helper + + void genFramebuffers(GLsizei n, GLuint* ids); + void deleteFramebuffers(GLsizei n, GLuint* ids); + void bindFramebuffer(GLenum target, GLuint framebuffer); void framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); - void renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); void framebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); + void drawBuffers(GLsizei n, const GLenum* bufs); + + void genRenderbuffers(GLsizei n, GLuint* renderbuffers); + void deleteRenderbuffers(GLsizei n, const GLuint* renderbuffers); + void bindRenderbuffer(GLenum target, GLuint renderbuffer); + void renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + + void clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void clear(GLbitfield mask); void enable(GLenum cap); void disable(GLenum cap); void blendFunc(GLenum sfactor, GLenum dfactor); + void drawArrays(GLenum mode, GLint first, GLsizei count); bool ok() const { return _ok; } + void reset(); protected: + void* getProcAddress(const char* symbol); + void check(const char* function, bool ok = true); + libretro::LoggerComponent* _logger; bool _ok; - void check(); + PFNGLGENBUFFERSPROC _glGenBuffers; + PFNGLDELETEBUFFERSPROC _glDeleteBuffers; + PFNGLBINDBUFFERPROC _glBindBuffer; + PFNGLBUFFERDATAPROC _glBufferData; + PFNGLVERTEXATTRIBPOINTERPROC _glVertexAttribPointer; + PFNGLENABLEVERTEXATTRIBARRAYPROC _glEnableVertexAttribArray; + + PFNGLCREATESHADERPROC _glCreateShader; + PFNGLDELETESHADERPROC _glDeleteShader; + PFNGLSHADERSOURCEPROC _glShaderSource; + PFNGLCOMPILESHADERPROC _glCompileShader; + PFNGLGETSHADERINFOLOGPROC _glGetShaderInfoLog; + + PFNGLCREATEPROGRAMPROC _glCreateProgram; + PFNGLDELETEPROGRAMPROC _glDeleteProgram; + PFNGLATTACHSHADERPROC _glAttachShader; + PFNGLLINKPROGRAMPROC _glLinkProgram; + PFNGLVALIDATEPROGRAMPROC _glValidateProgram; + PFNGLGETPROGRAMINFOLOGPROC _glGetProgramInfoLog; + PFNGLUSEPROGRAMPROC _glUseProgram; + PFNGLGETATTRIBLOCATIONPROC _glGetAttribLocation; + PFNGLGETUNIFORMLOCATIONPROC _glGetUniformLocation; + PFNGLUNIFORM2FPROC _glUniform2f; + + PFNGLGENFRAMEBUFFERSPROC _glGenFramebuffers; + PFNGLDELETEFRAMEBUFFERSPROC _glDeleteFramebuffers; + PFNGLBINDFRAMEBUFFERPROC _glBindFramebuffer; + PFNGLFRAMEBUFFERTEXTURE2DPROC _glFramebufferTexture2D; + PFNGLFRAMEBUFFERRENDERBUFFERPROC _glFramebufferRenderbuffer; + PFNGLDRAWBUFFERSPROC _glDrawBuffers; - PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; - PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; - PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; - PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; - PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; - PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; + PFNGLGENRENDERBUFFERSPROC _glGenRenderbuffers; + PFNGLDELETERENDERBUFFERSPROC _glDeleteRenderbuffers; + PFNGLBINDRENDERBUFFERPROC _glBindRenderbuffer; + PFNGLRENDERBUFFERSTORAGEPROC _glRenderbufferStorage; }; diff --git a/src/RALibretro.vcxproj b/src/RALibretro.vcxproj index 7315b80..d1656fc 100644 --- a/src/RALibretro.vcxproj +++ b/src/RALibretro.vcxproj @@ -65,7 +65,7 @@ true - $(SolutionDir)bin\$(Configuration) + $(SolutionDir)bin\$(Configuration)\ true @@ -85,7 +85,7 @@ true Windows $(MSBuildProjectDirectory)\..\SDL2\lib\x86;%(AdditionalLibraryDirectories) - SDL2main.lib;SDL2.lib;dinput8.lib;dxguid.lib;winmm.lib;imm32.lib;version.lib;winhttp.lib;%(AdditionalDependencies) + SDL2main.lib;SDL2.lib;dinput8.lib;dxguid.lib;winmm.lib;imm32.lib;version.lib;winhttp.lib;opengl32.lib;%(AdditionalDependencies) @@ -119,6 +119,7 @@ + @@ -143,6 +144,7 @@ + diff --git a/src/RALibretro.vcxproj.filters b/src/RALibretro.vcxproj.filters index 8683f8a..397115d 100644 --- a/src/RALibretro.vcxproj.filters +++ b/src/RALibretro.vcxproj.filters @@ -78,6 +78,9 @@ Source Files + + Source Files + @@ -152,6 +155,9 @@ Header Files + + Header Files + diff --git a/src/components/Video.cpp b/src/components/Video.cpp index ef1a24c..4fdf000 100644 --- a/src/components/Video.cpp +++ b/src/components/Video.cpp @@ -18,240 +18,276 @@ along with Foobar. If not, see . */ #include "Video.h" +#include "Gl.h" + +#include -#include #include -bool Video::init(libretro::LoggerComponent* logger, Config* config, SDL_Renderer* renderer) +bool Video::init(libretro::LoggerComponent* logger, Config* config) { _logger = logger; _config = config; - _inited = false; - - _renderer = renderer; - _texture = NULL; _linearFilter = false; - _width = _height = 0; + _windowWidth = _windowHeight = 0; + _textureWidth = _textureHeight = 0; + _viewWidth = _viewHeight = 0; + + _program = 0; + _posAttribute = -1; + _uvAttribute = -1; + _ratioUniform = -1; + _vertexBuffer = 0; + _texture = 0; + _framebuffer = 0; + _renderbuffer = 0; + + if (!_gl.init(logger)) + { + return false; + } + + createProgram(); + createVertexAttributes(); + + if (!_gl.ok()) + { + destroy(); + return false; + } + return true; } void Video::destroy() { - /*if (_texture != NULL) + if (_renderbuffer != 0) { - SDL_DestroyTexture(_texture); - _texture = NULL; - }*/ + _gl.reset(); + _gl.deleteRenderbuffers(1, &_renderbuffer); + _renderbuffer = 0; + } + + if (_framebuffer != 0) + { + _gl.reset(); + _gl.deleteFramebuffers(1, &_framebuffer); + _framebuffer = 0; + } + + if (_texture != 0) + { + _gl.reset(); + _gl.deleteTextures(1, &_texture); + _texture = 0; + } + + if (_vertexBuffer != 0) + { + _gl.reset(); + _gl.deleteBuffers(1, &_vertexBuffer); + _vertexBuffer = 0; + } + + if (_program != 0) + { + _gl.reset(); + _gl.deleteProgram(_program); + _program = 0; + } } void Video::draw() { -#if 0 - if (_texture != NULL) + if (_texture != 0) { + _gl.reset(); + bool linearFilter = _config->linearFilter(); if (linearFilter != _linearFilter) { - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, linearFilter ? "linear" : "nearest"); _linearFilter = linearFilter; - - setGeometry(_width, _height, _aspect, _pixelFormat, false); - } - - int w, h; - - if (SDL_GetRendererOutputSize(_renderer, &w, &h) != 0) - { - _logger->printf(RETRO_LOG_ERROR, "SDL_GetRendererOutputSize: %s", SDL_GetError()); - return; + GLint filter = linearFilter ? GL_LINEAR : GL_NEAREST; + _gl.texParameteri(_texture, GL_TEXTURE_MIN_FILTER, filter); + _gl.texParameteri(_texture, GL_TEXTURE_MAG_FILTER, filter); } - float height = h; + float height = _windowHeight; float width = height * _aspect; - if (width > w) + if (width > _windowWidth) { - width = w; + width = _windowWidth; height = width / _aspect; } - SDL_Rect src; - src.x = src.y = 0; - src.w = _width; - src.h = _height; - - int res; + float sx = 1.0f; + float sy = 1.0f; if (_config->preserveAspect()) { - SDL_Rect dst; - dst.w = ceil(width); - dst.h = ceil(height); - dst.x = (w - dst.w) / 2; - dst.y = (h - dst.h) / 2; - - res = SDL_RenderCopy(_renderer, _texture, &src, &dst); - } - else - { - res = SDL_RenderCopy(_renderer, _texture, &src, NULL); + sx = (float)_viewWidth / (float)_windowWidth; + sy = (float)_viewHeight / (float)_windowHeight; } - if (res != 0) - { - _logger->printf(RETRO_LOG_ERROR, "SDL_RenderCopy: %s", SDL_GetError()); - return; - } + _gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); + _gl.clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + _gl.useProgram(_program); + _gl.enableVertexAttribArray(_posAttribute); + _gl.enableVertexAttribArray(_uvAttribute); + _gl.uniform2f(_ratioUniform, sx, sy); + + _gl.drawArrays(GL_TRIANGLES, 0, 3); } -#endif } -bool Video::setGeometry(unsigned width, unsigned height, float aspect, enum retro_pixel_format pixelFormat, bool needsHardwareRender) +bool Video::setGeometry(unsigned width, unsigned height, float aspect, enum retro_pixel_format pixelFormat, const struct retro_hw_render_callback* hwRenderCallback) { -#if 0 - if (_inited) - { - // Destroy everything - } - - Gl gl(_logger); - - GLuint _framebuffer; - gl.genFramebuffers(1, &_framebuffer); - gl.bindFramebuffer(GL_FRAMEBUFFER, _framebuffer); - - GLuint _texture; - gl.genTextures(1, &_texture); - gl.bindTexture(GL_TEXTURE_2D, _texture); - - gl.texImage2D(GL_TEXTURE_2D, 0,GL_RGB, 1024, 768, 0,GL_RGB, GL_UNSIGNED_BYTE, 0); - - gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _texture, 0); + destroy(); + _gl.reset(); - GLuint _depth; - gl.genRenderbuffers(1, &_depth); - gl.bindRenderbuffer(GL_RENDERBUFFER, _depth); - gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); - gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); + _gl.genTextures(1, &_texture); - GLenum drawBuffers[1] = {GL_COLOR_ATTACHMENT0}; - gl.drawBuffers(1, drawBuffers); - - - - - - - - // TODO implement an OpenGL renderer - (void)needsHardwareRender; - - if (_texture != NULL) + if (!_gl.ok()) { - SDL_DestroyTexture(_texture); + return false; } - unsigned format; + _gl.bindTexture(GL_TEXTURE_2D, _texture); switch (pixelFormat) { case RETRO_PIXEL_FORMAT_XRGB8888: - format = SDL_PIXELFORMAT_ARGB8888; + _gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); break; case RETRO_PIXEL_FORMAT_RGB565: - format = SDL_PIXELFORMAT_RGB565; + _gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL); break; case RETRO_PIXEL_FORMAT_0RGB1555: default: - format = SDL_PIXELFORMAT_ARGB1555; + _gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL); break; } - _texture = SDL_CreateTexture(_renderer, format, SDL_TEXTUREACCESS_STREAMING, width, height); + _textureWidth = width; + _textureHeight = height; + _aspect = aspect; + _pixelFormat = pixelFormat; - if (_texture == NULL) + _logger->printf(RETRO_LOG_DEBUG, "Geometry set to %u x %u (1:%f)", width, height, aspect); + + if (hwRenderCallback != NULL) { - _logger->printf(RETRO_LOG_ERROR, "SDL_CreateTexture: %s", SDL_GetError()); - return false; + // Hardware framebuffer + _gl.genFramebuffers(1, &_framebuffer); + _gl.bindFramebuffer(GL_FRAMEBUFFER, _framebuffer); + + _gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); + + _gl.genRenderbuffers(1, &_renderbuffer); + _gl.bindRenderbuffer(GL_RENDERBUFFER, _renderbuffer); + GLenum internalFormat = hwRenderCallback->stencil ? GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT24; + _gl.renderbufferStorage(GL_RENDERBUFFER, internalFormat, width, height); + _gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderbuffer); + + GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0}; + _gl.drawBuffers(sizeof(drawBuffers) / sizeof(drawBuffers[0]), drawBuffers); } - if (SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_NONE) != 0) + if (!_gl.ok()) { - _logger->printf(RETRO_LOG_ERROR, "SDL_SetTextureBlendMode: %s", SDL_GetError()); + destroy(); return false; } - _textureWidth = width; - _textureHeight = height; - _pixelFormat = pixelFormat; - _aspect = aspect; -#endif - return true; } void Video::refresh(const void* data, unsigned width, unsigned height, size_t pitch) { -#if 0 if (data != NULL && data != RETRO_HW_FRAME_BUFFER_VALID) { - SDL_Rect rect; - rect.x = 0; - rect.y = 0; - rect.w = width; - rect.h = height; + _gl.reset(); - uint8_t* target_pixels; - int target_pitch; + _gl.bindTexture(GL_TEXTURE_2D, _texture); + uint8_t* p = (uint8_t*)data; - if (SDL_LockTexture(_texture, &rect, (void**)&target_pixels, &target_pitch) != 0) + switch (_pixelFormat) { - _logger->printf(RETRO_LOG_ERROR, "SDL_LockTexture: %s", SDL_GetError()); - return; + case RETRO_PIXEL_FORMAT_XRGB8888: + { + uint32_t* q = (uint32_t*)alloca(width * 4); + + if (q != NULL) + { + for (unsigned y = 0; y < height; y++) + { + uint32_t* r = q; + uint32_t* s = (uint32_t*)p; + + for (unsigned x = 0; x < width; x++) + { + uint32_t color = *s++; + uint32_t red = (color >> 16) & 255; + uint32_t green = (color >> 8) & 255; + uint32_t blue = color & 255; + *r++ = 0xff000000UL | blue << 16 | green << 8 | red; + } + + _gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, y, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)q); + p += pitch; + } + } + } + + break; + + case RETRO_PIXEL_FORMAT_RGB565: + for (unsigned y = 0; y < height; y++) + { + _gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, y, width, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, (void*)p); + p += pitch; + } + + break; + + case RETRO_PIXEL_FORMAT_0RGB1555: + default: + for (unsigned y = 0; y < height; y++) + { + _gl.texSubImage2D(GL_TEXTURE_2D, 0, 0, y, width, 1, GL_RGB, GL_UNSIGNED_SHORT_1_5_5_5_REV, (void*)p); + p += pitch; + } + + break; } - auto source_pixels = (uint8_t*)data; - size_t bpp = _pixelFormat == RETRO_PIXEL_FORMAT_XRGB8888 ? 4 : 2; - size_t bytes = width * bpp; - - if (bytes > (unsigned)target_pitch) + if (width != _viewWidth || height != _viewHeight) { - bytes = target_pitch; - } + _viewWidth = width; + _viewHeight = height; - for (unsigned y = 0; y < height; y++) - { - memcpy(target_pixels, source_pixels, bytes); - source_pixels += pitch; - target_pixels += target_pitch; + _logger->printf(RETRO_LOG_DEBUG, "Video refreshed with geometry %u x %u", width, height); } - - SDL_UnlockTexture(_texture); - - _width = width; - _height = height; } -#endif } bool Video::supportsContext(enum retro_hw_context_type type) { - // TODO Do we really support all those types? + // Do we really support those two? switch (type) { case RETRO_HW_CONTEXT_OPENGL: - case RETRO_HW_CONTEXT_OPENGLES2: + //case RETRO_HW_CONTEXT_OPENGLES2: case RETRO_HW_CONTEXT_OPENGL_CORE: - case RETRO_HW_CONTEXT_OPENGLES3: - case RETRO_HW_CONTEXT_OPENGLES_VERSION: + //case RETRO_HW_CONTEXT_OPENGLES3: + //case RETRO_HW_CONTEXT_OPENGLES_VERSION: return true; default: @@ -276,8 +312,15 @@ void Video::showMessage(const char* msg, unsigned frames) _logger->printf(RETRO_LOG_INFO, "OSD message (%u): %s", frames, msg); } +void Video::windowResized(unsigned width, unsigned height) +{ + _windowWidth = width; + _windowHeight = height; +} + const void* Video::getFramebuffer(unsigned* width, unsigned* height, unsigned* pitch, enum retro_pixel_format* format) { +#if 0 unsigned bpp = _pixelFormat == RETRO_PIXEL_FORMAT_XRGB8888 ? 4 : 2; void* result = malloc(_width * _height * bpp); @@ -325,4 +368,54 @@ const void* Video::getFramebuffer(unsigned* width, unsigned* height, unsigned* p *pitch = target_pitch; *format = _pixelFormat; return result; -} \ No newline at end of file +#endif + return NULL; +} + +void Video::createProgram() +{ + static const char* s_vertexShader = + "attribute vec2 a_pos;\n" + "attribute vec2 a_uv;\n" + "varying vec2 v_uv;\n" + "uniform vec2 u_ratio;\n" + "void main() {\n" + " v_uv = a_uv;\n" + " gl_Position = vec4(a_pos * u_ratio, 0.0, 1.0);\n" + "}"; + + static const char* s_fragmentShader = + "varying vec2 v_uv;\n" + "uniform sampler2D u_tex;\n" + "void main() {\n" + " gl_FragColor = texture2D(u_tex, v_uv);\n" + "}"; + + _program = _gl.createProgram(s_vertexShader, s_fragmentShader); + + _posAttribute = _gl.getAttribLocation(_program, "a_pos"); + _uvAttribute = _gl.getAttribLocation(_program, "a_uv"); + _ratioUniform = _gl.getUniformLocation(_program, "u_ratio"); +} + +void Video::createVertexAttributes() +{ + struct VertexData + { + float x, y, u, v; + }; + + static const VertexData vertexData[] = { + {-1.0f, -1.0f, 0.0f, 0.0f}, + {-1.0f, 1.0f, 0.0f, 1.0f}, + { 1.0f, -1.0f, 1.0f, 0.0f}, + { 1.0f, 1.0f, 1.0f, 1.0f} + }; + + _gl.genBuffers(1, &_vertexBuffer); + _gl.bindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); + _gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW); + + _gl.vertexAttribPointer(_posAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (const GLvoid*)offsetof(VertexData, x)); + _gl.vertexAttribPointer(_uvAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (const GLvoid*)offsetof(VertexData, u)); +} diff --git a/src/components/Video.h b/src/components/Video.h index b4a9d51..4f304a7 100644 --- a/src/components/Video.h +++ b/src/components/Video.h @@ -21,18 +21,19 @@ along with Foobar. If not, see . #include "libretro/Components.h" #include "Config.h" +#include "Gl.h" -#include +#include class Video: public libretro::VideoComponent { public: - bool init(libretro::LoggerComponent* logger, Config* config, SDL_Renderer* renderer); + bool init(libretro::LoggerComponent* logger, Config* config); void destroy(); void draw(); - virtual bool setGeometry(unsigned width, unsigned height, float aspect, enum retro_pixel_format pixelFormat, bool needsHardwareRender) override; + virtual bool setGeometry(unsigned width, unsigned height, float aspect, enum retro_pixel_format pixelFormat, const struct retro_hw_render_callback* hwRenderCallback) override; virtual void refresh(const void* data, unsigned width, unsigned height, size_t pitch) override; virtual bool supportsContext(enum retro_hw_context_type type) override; @@ -41,21 +42,34 @@ class Video: public libretro::VideoComponent virtual void showMessage(const char* msg, unsigned frames) override; + void windowResized(unsigned width, unsigned height); const void* getFramebuffer(unsigned* width, unsigned* height, unsigned* pitch, enum retro_pixel_format* format); protected: + void createProgram(); + void createVertexAttributes(); + + libretro::LoggerComponent* _logger; Config* _config; + Gl _gl; - bool _inited; + GLuint _program; + GLint _posAttribute; + GLint _uvAttribute; + GLint _ratioUniform; + GLuint _vertexBuffer; + GLuint _texture; + GLuint _framebuffer; + GLuint _renderbuffer; - SDL_Renderer* _renderer; - SDL_Texture* _texture; bool _linearFilter; + unsigned _windowWidth; + unsigned _windowHeight; unsigned _textureWidth; unsigned _textureHeight; + unsigned _viewWidth; + unsigned _viewHeight; enum retro_pixel_format _pixelFormat; - unsigned _width; - unsigned _height; float _aspect; }; diff --git a/src/libretro/Components.h b/src/libretro/Components.h index f0066c6..9930666 100644 --- a/src/libretro/Components.h +++ b/src/libretro/Components.h @@ -70,7 +70,7 @@ namespace libretro class VideoComponent { public: - virtual bool setGeometry(unsigned width, unsigned height, float aspect, enum retro_pixel_format pixelFormat, bool needsHardwareRender) = 0; + virtual bool setGeometry(unsigned width, unsigned height, float aspect, enum retro_pixel_format pixelFormat, const struct retro_hw_render_callback* hwRenderCallback) = 0; virtual void refresh(const void* data, unsigned width, unsigned height, size_t pitch) = 0; virtual bool supportsContext(enum retro_hw_context_type type) = 0; diff --git a/src/libretro/Core.cpp b/src/libretro/Core.cpp index ae1f5c5..2f08087 100644 --- a/src/libretro/Core.cpp +++ b/src/libretro/Core.cpp @@ -107,12 +107,12 @@ namespace class Video: public libretro::VideoComponent { public: - virtual bool setGeometry(unsigned width, unsigned height, float aspect, enum retro_pixel_format pixelFormat, bool needsHardwareRender) override + virtual bool setGeometry(unsigned width, unsigned height, float aspect, enum retro_pixel_format pixelFormat, const struct retro_hw_render_callback* hwRenderCallback) override { (void)width; (void)height; (void)pixelFormat; - (void)needsHardwareRender; + (void)hwRenderCallback; return false; } @@ -492,7 +492,9 @@ bool libretro::Core::initAV() _systemAVInfo.geometry.aspect_ratio = (float)_systemAVInfo.geometry.base_width / (float)_systemAVInfo.geometry.base_height; } - if (!_video->setGeometry(_systemAVInfo.geometry.base_width, _systemAVInfo.geometry.base_height, _systemAVInfo.geometry.aspect_ratio, _pixelFormat, _needsHardwareRender)) + const struct retro_hw_render_callback* cb = _needsHardwareRender ? &_hardwareRenderCallback : NULL; + + if (!_video->setGeometry(_systemAVInfo.geometry.base_width, _systemAVInfo.geometry.base_height, _systemAVInfo.geometry.aspect_ratio, _pixelFormat, cb)) { goto error; } @@ -921,7 +923,9 @@ bool libretro::Core::setSystemAVInfo(const struct retro_system_av_info* data) _systemAVInfo.geometry.aspect_ratio = (float)_systemAVInfo.geometry.base_width / (float)_systemAVInfo.geometry.base_height; } - if (!_video->setGeometry(_systemAVInfo.geometry.base_width, _systemAVInfo.geometry.base_height, _systemAVInfo.geometry.aspect_ratio, _pixelFormat, _needsHardwareRender)) + const struct retro_hw_render_callback* cb = _needsHardwareRender ? &_hardwareRenderCallback : NULL; + + if (!_video->setGeometry(_systemAVInfo.geometry.base_width, _systemAVInfo.geometry.base_height, _systemAVInfo.geometry.aspect_ratio, _pixelFormat, cb)) { return false; } @@ -1215,7 +1219,9 @@ bool libretro::Core::setGeometry(const struct retro_game_geometry* data) _systemAVInfo.geometry.aspect_ratio = (float)_systemAVInfo.geometry.base_width / _systemAVInfo.geometry.base_height; } - if (!_video->setGeometry(_systemAVInfo.geometry.base_width, _systemAVInfo.geometry.base_height, _systemAVInfo.geometry.aspect_ratio, _pixelFormat, _needsHardwareRender)) + const struct retro_hw_render_callback* cb = _needsHardwareRender ? &_hardwareRenderCallback : NULL; + + if (!_video->setGeometry(_systemAVInfo.geometry.base_width, _systemAVInfo.geometry.base_height, _systemAVInfo.geometry.aspect_ratio, _pixelFormat, cb)) { return false; } diff --git a/src/main.cpp b/src/main.cpp index 81ed700..3a1062a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,8 +56,8 @@ int main(int argc, char* argv[]) if (ok) { app.run(); + app.destroy(); } - app.destroy(); return ok ? 0 : 1; }