MYST3: Improve the node transition performance
On 4K displays, taking a screenshot and processing the pixels on the CPU was taking a noticeable amount of time. Now the screenshot is copied directly to a texture without going through the CPU.
This commit is contained in:
parent
93929be2c1
commit
056912f4b2
11 changed files with 99 additions and 27 deletions
|
@ -95,6 +95,17 @@ void Renderer::freeFont() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture *Renderer::copyScreenshotToTexture() {
|
||||||
|
Graphics::Surface *surface = getScreenshot();
|
||||||
|
|
||||||
|
Texture *texture = createTexture(surface);
|
||||||
|
|
||||||
|
surface->free();
|
||||||
|
delete surface;
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
Common::Rect Renderer::getFontCharacterRect(uint8 character) {
|
Common::Rect Renderer::getFontCharacterRect(uint8 character) {
|
||||||
uint index = 0;
|
uint index = 0;
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,7 @@ public:
|
||||||
virtual void draw2DText(const Common::String &text, const Common::Point &position) = 0;
|
virtual void draw2DText(const Common::String &text, const Common::Point &position) = 0;
|
||||||
|
|
||||||
virtual Graphics::Surface *getScreenshot() = 0;
|
virtual Graphics::Surface *getScreenshot() = 0;
|
||||||
|
virtual Texture *copyScreenshotToTexture();
|
||||||
|
|
||||||
/** Render a Drawable in the specified window */
|
/** Render a Drawable in the specified window */
|
||||||
void renderDrawable(Drawable *drawable, Window *window);
|
void renderDrawable(Drawable *drawable, Window *window);
|
||||||
|
|
|
@ -168,10 +168,14 @@ void OpenGLRenderer::drawTexturedRect2D(const Common::Rect &screenRect, const Co
|
||||||
const float tTop = textureRect.top / (float)glTexture->internalHeight;
|
const float tTop = textureRect.top / (float)glTexture->internalHeight;
|
||||||
const float tHeight = textureRect.height() / (float)glTexture->internalHeight;
|
const float tHeight = textureRect.height() / (float)glTexture->internalHeight;
|
||||||
|
|
||||||
const float sLeft = screenRect.left;
|
float sLeft = screenRect.left;
|
||||||
const float sTop = screenRect.top;
|
float sTop = screenRect.top;
|
||||||
const float sWidth = screenRect.width();
|
float sRight = sLeft + screenRect.width();
|
||||||
const float sHeight = screenRect.height();
|
float sBottom = sTop + screenRect.height();
|
||||||
|
|
||||||
|
if (glTexture->upsideDown) {
|
||||||
|
SWAP(sTop, sBottom);
|
||||||
|
}
|
||||||
|
|
||||||
if (transparency >= 0.0) {
|
if (transparency >= 0.0) {
|
||||||
if (additiveBlending) {
|
if (additiveBlending) {
|
||||||
|
@ -192,16 +196,16 @@ void OpenGLRenderer::drawTexturedRect2D(const Common::Rect &screenRect, const Co
|
||||||
glBindTexture(GL_TEXTURE_2D, glTexture->id);
|
glBindTexture(GL_TEXTURE_2D, glTexture->id);
|
||||||
glBegin(GL_TRIANGLE_STRIP);
|
glBegin(GL_TRIANGLE_STRIP);
|
||||||
glTexCoord2f(tLeft, tTop + tHeight);
|
glTexCoord2f(tLeft, tTop + tHeight);
|
||||||
glVertex3f(sLeft + 0, sTop + sHeight, 1.0f);
|
glVertex3f(sLeft + 0, sBottom, 1.0f);
|
||||||
|
|
||||||
glTexCoord2f(tLeft + tWidth, tTop + tHeight);
|
glTexCoord2f(tLeft + tWidth, tTop + tHeight);
|
||||||
glVertex3f(sLeft + sWidth, sTop + sHeight, 1.0f);
|
glVertex3f(sRight, sBottom, 1.0f);
|
||||||
|
|
||||||
glTexCoord2f(tLeft, tTop);
|
glTexCoord2f(tLeft, tTop);
|
||||||
glVertex3f(sLeft + 0, sTop + 0, 1.0f);
|
glVertex3f(sLeft + 0, sTop + 0, 1.0f);
|
||||||
|
|
||||||
glTexCoord2f(tLeft + tWidth, tTop);
|
glTexCoord2f(tLeft + tWidth, tTop);
|
||||||
glVertex3f(sLeft + sWidth, sTop + 0, 1.0f);
|
glVertex3f(sRight, sTop + 0, 1.0f);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
@ -328,6 +332,15 @@ Graphics::Surface *OpenGLRenderer::getScreenshot() {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture *OpenGLRenderer::copyScreenshotToTexture() {
|
||||||
|
OpenGLTexture *texture = new OpenGLTexture();
|
||||||
|
|
||||||
|
Common::Rect screen = viewport();
|
||||||
|
texture->copyFromFramebuffer(screen);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Myst3
|
} // End of namespace Myst3
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -55,6 +55,8 @@ public:
|
||||||
virtual void draw2DText(const Common::String &text, const Common::Point &position) override;
|
virtual void draw2DText(const Common::String &text, const Common::Point &position) override;
|
||||||
|
|
||||||
virtual Graphics::Surface *getScreenshot() override;
|
virtual Graphics::Surface *getScreenshot() override;
|
||||||
|
Texture *copyScreenshotToTexture() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void drawFace(uint face, Texture *texture);
|
void drawFace(uint face, Texture *texture);
|
||||||
};
|
};
|
||||||
|
|
|
@ -249,6 +249,7 @@ void ShaderRenderer::drawTexturedRect2D(const Common::Rect &screenRect, const Co
|
||||||
_boxShader->setUniform("verSizeWH", scaled(sWidth, sHeight));
|
_boxShader->setUniform("verSizeWH", scaled(sWidth, sHeight));
|
||||||
_boxShader->setUniform("texOffsetXY", Math::Vector2d(tLeft, tTop));
|
_boxShader->setUniform("texOffsetXY", Math::Vector2d(tLeft, tTop));
|
||||||
_boxShader->setUniform("texSizeWH", Math::Vector2d(tWidth, tHeight));
|
_boxShader->setUniform("texSizeWH", Math::Vector2d(tWidth, tHeight));
|
||||||
|
_boxShader->setUniform("flipY", glTexture->upsideDown);
|
||||||
|
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
|
@ -398,6 +399,15 @@ Graphics::Surface *ShaderRenderer::getScreenshot() {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture *ShaderRenderer::copyScreenshotToTexture() {
|
||||||
|
OpenGLTexture *texture = new OpenGLTexture();
|
||||||
|
|
||||||
|
Common::Rect screen = viewport();
|
||||||
|
texture->copyFromFramebuffer(screen);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Myst3
|
} // End of namespace Myst3
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -56,6 +56,7 @@ public:
|
||||||
virtual void draw2DText(const Common::String &text, const Common::Point &position) override;
|
virtual void draw2DText(const Common::String &text, const Common::Point &position) override;
|
||||||
|
|
||||||
virtual Graphics::Surface *getScreenshot() override;
|
virtual Graphics::Surface *getScreenshot() override;
|
||||||
|
Texture *copyScreenshotToTexture() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupQuadEBO();
|
void setupQuadEBO();
|
||||||
|
|
|
@ -42,10 +42,20 @@ static uint32 upperPowerOfTwo(uint32 v) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenGLTexture::OpenGLTexture() :
|
||||||
|
internalFormat(0),
|
||||||
|
sourceFormat(0),
|
||||||
|
internalWidth(0),
|
||||||
|
internalHeight(0),
|
||||||
|
upsideDown(false) {
|
||||||
|
glGenTextures(1, &id);
|
||||||
|
}
|
||||||
|
|
||||||
OpenGLTexture::OpenGLTexture(const Graphics::Surface *surface) {
|
OpenGLTexture::OpenGLTexture(const Graphics::Surface *surface) {
|
||||||
width = surface->w;
|
width = surface->w;
|
||||||
height = surface->h;
|
height = surface->h;
|
||||||
format = surface->format;
|
format = surface->format;
|
||||||
|
upsideDown = false;
|
||||||
|
|
||||||
// Pad the textures if non power of two support is unavailable
|
// Pad the textures if non power of two support is unavailable
|
||||||
if (OpenGLContext.NPOTSupported) {
|
if (OpenGLContext.NPOTSupported) {
|
||||||
|
@ -90,7 +100,7 @@ void OpenGLTexture::update(const Graphics::Surface *surface) {
|
||||||
updatePartial(surface, Common::Rect(surface->w, surface->h));
|
updatePartial(surface, Common::Rect(surface->w, surface->h));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLTexture::updateTexture(const Graphics::Surface* surface, const Common::Rect& rect) {
|
void OpenGLTexture::updateTexture(const Graphics::Surface *surface, const Common::Rect &rect) {
|
||||||
assert(surface->format == format);
|
assert(surface->format == format);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, id);
|
glBindTexture(GL_TEXTURE_2D, id);
|
||||||
|
@ -111,6 +121,28 @@ void OpenGLTexture::updatePartial(const Graphics::Surface *surface, const Common
|
||||||
updateTexture(surface, rect);
|
updateTexture(surface, rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLTexture::copyFromFramebuffer(const Common::Rect &screen) {
|
||||||
|
internalFormat = GL_RGB;
|
||||||
|
width = screen.width();
|
||||||
|
height = screen.height();
|
||||||
|
upsideDown = true;
|
||||||
|
|
||||||
|
// Pad the textures if non power of two support is unavailable
|
||||||
|
if (OpenGLContext.NPOTSupported) {
|
||||||
|
internalHeight = height;
|
||||||
|
internalWidth = width;
|
||||||
|
} else {
|
||||||
|
internalHeight = upperPowerOfTwo(height);
|
||||||
|
internalWidth = upperPowerOfTwo(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, id);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glCopyTexImage2D(GL_TEXTURE_2D, 0, internalFormat, screen.left, screen.top, internalWidth, internalHeight, 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Myst3
|
} // End of namespace Myst3
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -34,16 +34,20 @@ namespace Myst3 {
|
||||||
class OpenGLTexture : public Texture {
|
class OpenGLTexture : public Texture {
|
||||||
public:
|
public:
|
||||||
OpenGLTexture(const Graphics::Surface *surface);
|
OpenGLTexture(const Graphics::Surface *surface);
|
||||||
|
OpenGLTexture();
|
||||||
virtual ~OpenGLTexture();
|
virtual ~OpenGLTexture();
|
||||||
|
|
||||||
void update(const Graphics::Surface *surface) override;
|
void update(const Graphics::Surface *surface) override;
|
||||||
void updatePartial(const Graphics::Surface *surface, const Common::Rect &rect) override;
|
void updatePartial(const Graphics::Surface *surface, const Common::Rect &rect) override;
|
||||||
|
|
||||||
|
void copyFromFramebuffer(const Common::Rect &screen);
|
||||||
|
|
||||||
GLuint id;
|
GLuint id;
|
||||||
GLuint internalFormat;
|
GLuint internalFormat;
|
||||||
GLuint sourceFormat;
|
GLuint sourceFormat;
|
||||||
uint32 internalWidth;
|
uint32 internalWidth;
|
||||||
uint32 internalHeight;
|
uint32 internalHeight;
|
||||||
|
bool upsideDown;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateTexture(const Graphics::Surface *surface, const Common::Rect &rect);
|
void updateTexture(const Graphics::Surface *surface, const Common::Rect &rect);
|
||||||
|
|
|
@ -5,6 +5,7 @@ uniform vec2 texOffsetXY;
|
||||||
uniform vec2 texSizeWH;
|
uniform vec2 texSizeWH;
|
||||||
uniform vec2 verOffsetXY;
|
uniform vec2 verOffsetXY;
|
||||||
uniform vec2 verSizeWH;
|
uniform vec2 verSizeWH;
|
||||||
|
uniform bool flipY;
|
||||||
|
|
||||||
out vec2 Texcoord;
|
out vec2 Texcoord;
|
||||||
|
|
||||||
|
@ -17,5 +18,9 @@ void main()
|
||||||
pos.x = pos.x * 2.0 - 1.0;
|
pos.x = pos.x * 2.0 - 1.0;
|
||||||
pos.y = -1.0 * (pos.y * 2.0 - 1.0);
|
pos.y = -1.0 * (pos.y * 2.0 - 1.0);
|
||||||
|
|
||||||
|
if (flipY) {
|
||||||
|
pos.y *= -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
gl_Position = vec4(pos, 0.0, 1.0);
|
gl_Position = vec4(pos, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,19 +38,15 @@ Transition::Transition(Myst3Engine *vm) :
|
||||||
_sourceScreenshot(nullptr),
|
_sourceScreenshot(nullptr),
|
||||||
_frameLimiter(new FrameLimiter(g_system, ConfMan.getInt("engine_speed"))) {
|
_frameLimiter(new FrameLimiter(g_system, ConfMan.getInt("engine_speed"))) {
|
||||||
|
|
||||||
int transitionSpeed = ConfMan.getInt("transition_speed");
|
|
||||||
|
|
||||||
// Capture a screenshot of the source node
|
// Capture a screenshot of the source node
|
||||||
if (transitionSpeed != 100) {
|
int durationTicks = computeDuration();
|
||||||
_sourceScreenshot = _vm->_gfx->getScreenshot();
|
if (durationTicks) {
|
||||||
|
_sourceScreenshot = _vm->_gfx->copyScreenshotToTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Transition::~Transition() {
|
Transition::~Transition() {
|
||||||
if (_sourceScreenshot) {
|
_vm->_gfx->freeTexture(_sourceScreenshot);
|
||||||
_sourceScreenshot->free();
|
|
||||||
delete _sourceScreenshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete _frameLimiter;
|
delete _frameLimiter;
|
||||||
}
|
}
|
||||||
|
@ -87,13 +83,7 @@ void Transition::draw(TransitionType type) {
|
||||||
|
|
||||||
// Capture a screenshot of the destination node
|
// Capture a screenshot of the destination node
|
||||||
_vm->drawFrame(true);
|
_vm->drawFrame(true);
|
||||||
Graphics::Surface *target = _vm->_gfx->getScreenshot();
|
Texture *targetScreenshot = _vm->_gfx->copyScreenshotToTexture();
|
||||||
|
|
||||||
Texture *sourceTexture = _vm->_gfx->createTexture(_sourceScreenshot);
|
|
||||||
Texture *targetTexture = _vm->_gfx->createTexture(target);
|
|
||||||
|
|
||||||
target->free();
|
|
||||||
delete target;
|
|
||||||
|
|
||||||
// Compute the start and end frames for the animation
|
// Compute the start and end frames for the animation
|
||||||
int startTick = _vm->_state->getTickCount();
|
int startTick = _vm->_state->getTickCount();
|
||||||
|
@ -109,7 +99,9 @@ void Transition::draw(TransitionType type) {
|
||||||
|
|
||||||
completion = CLIP<int>(100 * (_vm->_state->getTickCount() - startTick) / durationTicks, 0, 100);
|
completion = CLIP<int>(100 * (_vm->_state->getTickCount() - startTick) / durationTicks, 0, 100);
|
||||||
|
|
||||||
drawStep(targetTexture, sourceTexture, completion);
|
_vm->_gfx->clear();
|
||||||
|
|
||||||
|
drawStep(targetScreenshot, _sourceScreenshot, completion);
|
||||||
|
|
||||||
_vm->_gfx->flipBuffer();
|
_vm->_gfx->flipBuffer();
|
||||||
_frameLimiter->delayBeforeSwap();
|
_frameLimiter->delayBeforeSwap();
|
||||||
|
@ -132,8 +124,9 @@ void Transition::draw(TransitionType type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_vm->_gfx->freeTexture(sourceTexture);
|
_vm->_gfx->freeTexture(targetScreenshot);
|
||||||
_vm->_gfx->freeTexture(targetTexture);
|
_vm->_gfx->freeTexture(_sourceScreenshot);
|
||||||
|
_sourceScreenshot = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transition::drawStep(Texture *targetTexture, Texture *sourceTexture, uint completion) {
|
void Transition::drawStep(Texture *targetTexture, Texture *sourceTexture, uint completion) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ private:
|
||||||
FrameLimiter *_frameLimiter;
|
FrameLimiter *_frameLimiter;
|
||||||
TransitionType _type;
|
TransitionType _type;
|
||||||
|
|
||||||
Graphics::Surface *_sourceScreenshot;
|
Texture *_sourceScreenshot;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue