mirror of https://github.com/OpenTTD/OpenTTD
Add: [OpenGL] Support for a separate animation buffer that stores the palette values of the screen in addition to the colour buffer.
parent
01ef44fa4f
commit
200be7d20c
|
@ -185,6 +185,14 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual Blitter::PaletteAnimation UsePaletteAnimation() = 0;
|
virtual Blitter::PaletteAnimation UsePaletteAnimation() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this blitter require a separate animation buffer from the video backend?
|
||||||
|
*/
|
||||||
|
virtual bool NeedsAnimationBuffer()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of the blitter, the same as the Factory-instance returns.
|
* Get the name of the blitter, the same as the Factory-instance returns.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -392,8 +392,10 @@ OpenGLBackend::~OpenGLBackend()
|
||||||
if (_glDeleteBuffers != nullptr) {
|
if (_glDeleteBuffers != nullptr) {
|
||||||
_glDeleteBuffers(1, &this->vbo_quad);
|
_glDeleteBuffers(1, &this->vbo_quad);
|
||||||
_glDeleteBuffers(1, &this->vid_pbo);
|
_glDeleteBuffers(1, &this->vid_pbo);
|
||||||
|
_glDeleteBuffers(1, &this->anim_pbo);
|
||||||
}
|
}
|
||||||
glDeleteTextures(1, &this->vid_texture);
|
glDeleteTextures(1, &this->vid_texture);
|
||||||
|
glDeleteTextures(1, &this->anim_texture);
|
||||||
glDeleteTextures(1, &this->pal_texture);
|
glDeleteTextures(1, &this->pal_texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,6 +460,17 @@ const char *OpenGLBackend::Init()
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
if (glGetError() != GL_NO_ERROR) return "Can't generate video buffer texture";
|
if (glGetError() != GL_NO_ERROR) return "Can't generate video buffer texture";
|
||||||
|
|
||||||
|
/* Setup video buffer texture. */
|
||||||
|
glGenTextures(1, &this->anim_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, this->anim_texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
if (glGetError() != GL_NO_ERROR) return "Can't generate animation buffer texture";
|
||||||
|
|
||||||
/* Setup palette texture. */
|
/* Setup palette texture. */
|
||||||
glGenTextures(1, &this->pal_texture);
|
glGenTextures(1, &this->pal_texture);
|
||||||
glBindTexture(GL_TEXTURE_1D, this->pal_texture);
|
glBindTexture(GL_TEXTURE_1D, this->pal_texture);
|
||||||
|
@ -505,10 +518,13 @@ const char *OpenGLBackend::Init()
|
||||||
_glUniform1i(tex_location, 0); // Texture unit 0.
|
_glUniform1i(tex_location, 0); // Texture unit 0.
|
||||||
_glUniform1i(palette_location, 1); // Texture unit 1.
|
_glUniform1i(palette_location, 1); // Texture unit 1.
|
||||||
_glUniform1i(remap_location, 2); // Texture unit 2.
|
_glUniform1i(remap_location, 2); // Texture unit 2.
|
||||||
|
(void)glGetError(); // Clear errors.
|
||||||
|
|
||||||
/* Create pixel buffer object as video buffer storage. */
|
/* Create pixel buffer object as video buffer storage. */
|
||||||
_glGenBuffers(1, &this->vid_pbo);
|
_glGenBuffers(1, &this->vid_pbo);
|
||||||
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vid_pbo);
|
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vid_pbo);
|
||||||
|
_glGenBuffers(1, &this->anim_pbo);
|
||||||
|
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
|
||||||
if (glGetError() != GL_NO_ERROR) return "Can't allocate pixel buffer for video buffer";
|
if (glGetError() != GL_NO_ERROR) return "Can't allocate pixel buffer for video buffer";
|
||||||
|
|
||||||
/* Prime vertex buffer with a full-screen quad and store
|
/* Prime vertex buffer with a full-screen quad and store
|
||||||
|
@ -686,7 +702,7 @@ bool OpenGLBackend::Resize(int w, int h, bool force)
|
||||||
if (!force && _screen.width == w && _screen.height == h) return false;
|
if (!force && _screen.width == w && _screen.height == h) return false;
|
||||||
|
|
||||||
int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
|
int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
|
||||||
int pitch = bpp != 32 ? Align(w, 4) : w;
|
int pitch = Align(w, 4);
|
||||||
|
|
||||||
glViewport(0, 0, w, h);
|
glViewport(0, 0, w, h);
|
||||||
|
|
||||||
|
@ -715,6 +731,23 @@ bool OpenGLBackend::Resize(int w, int h, bool force)
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Does this blitter need a separate animation buffer? */
|
||||||
|
if (BlitterFactory::GetCurrentBlitter()->NeedsAnimationBuffer()) {
|
||||||
|
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
|
||||||
|
_glBufferData(GL_PIXEL_UNPACK_BUFFER, pitch * h, NULL, GL_DYNAMIC_READ); // Buffer content has to persist from frame to frame and is read back by the blitter, which means a READ usage hint.
|
||||||
|
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, this->anim_texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
} else {
|
||||||
|
/* Allocate dummy texture that always reads as 0 == no remap. */
|
||||||
|
uint dummy = 0;
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, this->anim_texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &dummy);
|
||||||
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
/* Set new viewport. */
|
/* Set new viewport. */
|
||||||
|
@ -761,7 +794,18 @@ void OpenGLBackend::Paint()
|
||||||
glBindTexture(GL_TEXTURE_2D, this->vid_texture);
|
glBindTexture(GL_TEXTURE_2D, this->vid_texture);
|
||||||
_glActiveTexture(GL_TEXTURE1);
|
_glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_1D, this->pal_texture);
|
glBindTexture(GL_TEXTURE_1D, this->pal_texture);
|
||||||
_glUseProgram(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 8 ? this->pal_program : this->vid_program);
|
/* Is the blitter relying on a separate animation buffer? */
|
||||||
|
if (BlitterFactory::GetCurrentBlitter()->NeedsAnimationBuffer()) {
|
||||||
|
_glActiveTexture(GL_TEXTURE2);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, this->anim_texture);
|
||||||
|
_glUseProgram(this->remap_program);
|
||||||
|
_glUniform4f(this->remap_sprite_loc, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
_glUniform2f(this->remap_screen_loc, 1.0f, 1.0f);
|
||||||
|
_glUniform1f(this->remap_zoom_loc, 0);
|
||||||
|
_glUniform1i(this->remap_rgb_loc, 1);
|
||||||
|
} else {
|
||||||
|
_glUseProgram(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 8 ? this->pal_program : this->vid_program);
|
||||||
|
}
|
||||||
_glBindVertexArray(this->vao_quad);
|
_glBindVertexArray(this->vao_quad);
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
@ -814,6 +858,18 @@ void *OpenGLBackend::GetVideoBuffer()
|
||||||
return _glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
|
return _glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a pointer to the memory for the separate animation buffer.
|
||||||
|
* @return Pointer to draw on.
|
||||||
|
*/
|
||||||
|
uint8 *OpenGLBackend::GetAnimBuffer()
|
||||||
|
{
|
||||||
|
if (this->anim_pbo == 0) return nullptr;
|
||||||
|
|
||||||
|
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
|
||||||
|
return (uint8 *)_glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update video buffer texture after the video buffer was filled.
|
* Update video buffer texture after the video buffer was filled.
|
||||||
* @param update_rect Rectangle encompassing the dirty region of the video buffer.
|
* @param update_rect Rectangle encompassing the dirty region of the video buffer.
|
||||||
|
@ -842,6 +898,26 @@ void OpenGLBackend::ReleaseVideoBuffer(const Rect &update_rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update animation buffer texture after the animation buffer was filled.
|
||||||
|
* @param update_rect Rectangle encompassing the dirty region of the animation buffer.
|
||||||
|
*/
|
||||||
|
void OpenGLBackend::ReleaseAnimBuffer(const Rect &update_rect)
|
||||||
|
{
|
||||||
|
if (this->anim_pbo == 0) return;
|
||||||
|
|
||||||
|
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->anim_pbo);
|
||||||
|
_glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||||
|
|
||||||
|
/* Update changed rect of the video buffer texture. */
|
||||||
|
if (update_rect.left != update_rect.right) {
|
||||||
|
_glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, this->anim_texture);
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, _screen.pitch);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, update_rect.left, update_rect.top, update_rect.right - update_rect.left, update_rect.bottom - update_rect.top, GL_RED, GL_UNSIGNED_BYTE, (GLvoid *)(size_t)(update_rect.top * _screen.pitch + update_rect.left));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* virtual */ Sprite *OpenGLBackend::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator)
|
/* virtual */ Sprite *OpenGLBackend::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator)
|
||||||
{
|
{
|
||||||
/* Allocate and construct sprite data. */
|
/* Allocate and construct sprite data. */
|
||||||
|
|
|
@ -39,6 +39,9 @@ private:
|
||||||
GLuint vbo_quad; ///< Vertex buffer with a fullscreen quad.
|
GLuint vbo_quad; ///< Vertex buffer with a fullscreen quad.
|
||||||
GLuint pal_texture; ///< Palette lookup texture.
|
GLuint pal_texture; ///< Palette lookup texture.
|
||||||
|
|
||||||
|
GLuint anim_pbo; ///< Pixel buffer object storing the memory used for the animation buffer.
|
||||||
|
GLuint anim_texture; ///< Texture handle for the animation buffer texture.
|
||||||
|
|
||||||
GLuint remap_program; ///< Shader program for blending and rendering a RGBA + remap texture.
|
GLuint remap_program; ///< Shader program for blending and rendering a RGBA + remap texture.
|
||||||
GLint remap_sprite_loc; ///< Uniform location for sprite parameters.
|
GLint remap_sprite_loc; ///< Uniform location for sprite parameters.
|
||||||
GLint remap_screen_loc; ///< Uniform location for screen size;
|
GLint remap_screen_loc; ///< Uniform location for screen size;
|
||||||
|
@ -72,7 +75,9 @@ public:
|
||||||
void ClearCursorCache();
|
void ClearCursorCache();
|
||||||
|
|
||||||
void *GetVideoBuffer();
|
void *GetVideoBuffer();
|
||||||
|
uint8 *GetAnimBuffer();
|
||||||
void ReleaseVideoBuffer(const Rect &update_rect);
|
void ReleaseVideoBuffer(const Rect &update_rect);
|
||||||
|
void ReleaseAnimBuffer(const Rect &update_rect);
|
||||||
|
|
||||||
/* SpriteEncoder */
|
/* SpriteEncoder */
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,24 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this video driver support a separate animation buffer in addition to the colour buffer?
|
||||||
|
* @return True if a separate animation buffer is supported.
|
||||||
|
*/
|
||||||
|
virtual bool HasAnimBuffer()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a pointer to the animation buffer of the video back-end.
|
||||||
|
* @return Pointer to the buffer or nullptr if no animation buffer is supported.
|
||||||
|
*/
|
||||||
|
virtual uint8 *GetAnimBuffer()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An edit box lost the input focus. Abort character compositing if necessary.
|
* An edit box lost the input focus. Abort character compositing if necessary.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1545,14 +1545,19 @@ bool VideoDriver_Win32OpenGL::AllocateBackingStore(int w, int h, bool force)
|
||||||
|
|
||||||
void *VideoDriver_Win32OpenGL::GetVideoPointer()
|
void *VideoDriver_Win32OpenGL::GetVideoPointer()
|
||||||
{
|
{
|
||||||
|
if (BlitterFactory::GetCurrentBlitter()->NeedsAnimationBuffer()) {
|
||||||
|
this->anim_buffer = OpenGLBackend::Get()->GetAnimBuffer();
|
||||||
|
}
|
||||||
return OpenGLBackend::Get()->GetVideoBuffer();
|
return OpenGLBackend::Get()->GetVideoBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDriver_Win32OpenGL::ReleaseVideoPointer()
|
void VideoDriver_Win32OpenGL::ReleaseVideoPointer()
|
||||||
{
|
{
|
||||||
|
if (this->anim_buffer != nullptr) OpenGLBackend::Get()->ReleaseAnimBuffer(this->dirty_rect);
|
||||||
OpenGLBackend::Get()->ReleaseVideoBuffer(this->dirty_rect);
|
OpenGLBackend::Get()->ReleaseVideoBuffer(this->dirty_rect);
|
||||||
this->dirty_rect = {};
|
this->dirty_rect = {};
|
||||||
_screen.dst_ptr = nullptr;
|
_screen.dst_ptr = nullptr;
|
||||||
|
this->anim_buffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDriver_Win32OpenGL::Paint()
|
void VideoDriver_Win32OpenGL::Paint()
|
||||||
|
|
|
@ -128,7 +128,7 @@ public:
|
||||||
/** The OpenGL video driver for windows. */
|
/** The OpenGL video driver for windows. */
|
||||||
class VideoDriver_Win32OpenGL : public VideoDriver_Win32Base {
|
class VideoDriver_Win32OpenGL : public VideoDriver_Win32Base {
|
||||||
public:
|
public:
|
||||||
VideoDriver_Win32OpenGL() : dc(nullptr), gl_rc(nullptr) {}
|
VideoDriver_Win32OpenGL() : dc(nullptr), gl_rc(nullptr), anim_buffer(nullptr) {}
|
||||||
|
|
||||||
const char *Start(const StringList ¶m) override;
|
const char *Start(const StringList ¶m) override;
|
||||||
|
|
||||||
|
@ -144,12 +144,16 @@ public:
|
||||||
|
|
||||||
void ClearSystemSprites() override;
|
void ClearSystemSprites() override;
|
||||||
|
|
||||||
|
bool HasAnimBuffer() override { return true; }
|
||||||
|
uint8 *GetAnimBuffer() override { return this->anim_buffer; }
|
||||||
|
|
||||||
const char *GetName() const override { return "win32-opengl"; }
|
const char *GetName() const override { return "win32-opengl"; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HDC dc; ///< Window device context.
|
HDC dc; ///< Window device context.
|
||||||
HGLRC gl_rc; ///< OpenGL context.
|
HGLRC gl_rc; ///< OpenGL context.
|
||||||
bool vsync; ///< Enable VSync?
|
bool vsync; ///< Enable VSync?
|
||||||
|
uint8 *anim_buffer; ///< Animation buffer from OpenGL back-end.
|
||||||
|
|
||||||
uint8 GetFullscreenBpp() override { return 32; } // OpenGL is always 32 bpp.
|
uint8 GetFullscreenBpp() override { return 32; } // OpenGL is always 32 bpp.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue