Commit 36e86234 by Bruce Dawson Committed by Jamie Madill

Improve image update perf by re-using a MemoryBuffer.

Instead of allocating a new MemoryBuffer every frame, we can store one scratch buffer in the Renderer, and occasionally re-create it to ensure we aren't stuck using the maximum amount of memory. BUG=angle:842 Change-Id: Id7c1912921ed8f84b151413453c3268d853352db Reviewed-on: https://chromium-review.googlesource.com/230861Tested-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarBruce Dawson <brucedawson@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 9d59a044
...@@ -32,26 +32,31 @@ bool MemoryBuffer::resize(size_t size) ...@@ -32,26 +32,31 @@ bool MemoryBuffer::resize(size_t size)
free(mData); free(mData);
mData = NULL; mData = NULL;
mSize = 0; mSize = 0;
return true;
} }
else
if (size == mSize)
{ {
uint8_t *newMemory = reinterpret_cast<uint8_t*>(malloc(sizeof(uint8_t) * size)); return true;
if (newMemory == NULL) }
{
return false;
}
if (mData) // Only reallocate if the size has changed.
{ uint8_t *newMemory = reinterpret_cast<uint8_t*>(malloc(sizeof(uint8_t) * size));
// Copy the intersection of the old data and the new data if (newMemory == NULL)
std::copy(mData, mData + std::min(mSize, size), newMemory); {
free(mData); return false;
} }
mData = newMemory; if (mData)
mSize = size; {
// Copy the intersection of the old data and the new data
std::copy(mData, mData + std::min(mSize, size), newMemory);
free(mData);
} }
mData = newMemory;
mSize = size;
return true; return true;
} }
......
...@@ -18,13 +18,23 @@ ...@@ -18,13 +18,23 @@
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/DisplayD3D.h" #include "libANGLE/renderer/d3d/DisplayD3D.h"
#include "libANGLE/renderer/d3d/IndexDataManager.h" #include "libANGLE/renderer/d3d/IndexDataManager.h"
#include "libANGLE/renderer/d3d/MemoryBuffer.h"
namespace rx namespace rx
{ {
namespace
{
// If we request a scratch buffer requesting a smaller size this many times,
// release and recreate the scratch buffer. This ensures we don't have a
// degenerate case where we are stuck hogging memory.
const int ScratchMemoryBufferLifetime = 1000;
}
RendererD3D::RendererD3D(egl::Display *display) RendererD3D::RendererD3D(egl::Display *display)
: mDisplay(display), : mDisplay(display),
mDeviceLost(false) mDeviceLost(false),
mScratchMemoryBufferResetCounter(0)
{ {
} }
...@@ -35,6 +45,7 @@ RendererD3D::~RendererD3D() ...@@ -35,6 +45,7 @@ RendererD3D::~RendererD3D()
void RendererD3D::cleanup() void RendererD3D::cleanup()
{ {
mScratchMemoryBuffer.resize(0);
for (auto &incompleteTexture : mIncompleteTextures) for (auto &incompleteTexture : mIncompleteTextures)
{ {
incompleteTexture.second.set(NULL); incompleteTexture.second.set(NULL);
...@@ -830,4 +841,34 @@ DisplayImpl *RendererD3D::createDisplay() ...@@ -830,4 +841,34 @@ DisplayImpl *RendererD3D::createDisplay()
return new DisplayD3D(this); return new DisplayD3D(this);
} }
gl::Error RendererD3D::getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut)
{
if (mScratchMemoryBuffer.size() == requestedSize)
{
mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime;
*bufferOut = &mScratchMemoryBuffer;
return gl::Error(GL_NO_ERROR);
}
if (mScratchMemoryBuffer.size() > requestedSize)
{
mScratchMemoryBufferResetCounter--;
}
if (mScratchMemoryBufferResetCounter <= 0 || mScratchMemoryBuffer.size() < requestedSize)
{
mScratchMemoryBuffer.resize(0);
if (!mScratchMemoryBuffer.resize(requestedSize))
{
return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer.");
}
mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime;
}
ASSERT(mScratchMemoryBuffer.size() >= requestedSize);
*bufferOut = &mScratchMemoryBuffer;
return gl::Error(GL_NO_ERROR);
}
} }
...@@ -9,9 +9,10 @@ ...@@ -9,9 +9,10 @@
#ifndef LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ #ifndef LIBANGLE_RENDERER_D3D_RENDERERD3D_H_
#define LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ #define LIBANGLE_RENDERER_D3D_RENDERERD3D_H_
#include "libANGLE/Data.h"
#include "libANGLE/renderer/Renderer.h" #include "libANGLE/renderer/Renderer.h"
#include "libANGLE/renderer/d3d/MemoryBuffer.h"
#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" #include "libANGLE/renderer/d3d/d3d11/NativeWindow.h"
#include "libANGLE/Data.h"
//FIXME(jmadill): std::array is currently prohibited by Chromium style guide //FIXME(jmadill): std::array is currently prohibited by Chromium style guide
#include <array> #include <array>
...@@ -25,15 +26,14 @@ class Texture; ...@@ -25,15 +26,14 @@ class Texture;
namespace rx namespace rx
{ {
class TextureStorage; class Image;
class VertexBuffer;
class IndexBuffer; class IndexBuffer;
class RenderTarget;
class ShaderExecutable; class ShaderExecutable;
class SwapChain; class SwapChain;
class RenderTarget;
class Image;
class TextureStorage; class TextureStorage;
class UniformStorage; class UniformStorage;
class VertexBuffer;
class RendererD3D : public Renderer class RendererD3D : public Renderer
{ {
...@@ -161,6 +161,8 @@ class RendererD3D : public Renderer ...@@ -161,6 +161,8 @@ class RendererD3D : public Renderer
void notifyDeviceLost() override; void notifyDeviceLost() override;
virtual bool resetDevice() = 0; virtual bool resetDevice() = 0;
gl::Error getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut);
protected: protected:
virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0; virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0;
virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
...@@ -204,6 +206,8 @@ class RendererD3D : public Renderer ...@@ -204,6 +206,8 @@ class RendererD3D : public Renderer
gl::Texture *getIncompleteTexture(GLenum type); gl::Texture *getIncompleteTexture(GLenum type);
gl::TextureMap mIncompleteTextures; gl::TextureMap mIncompleteTextures;
MemoryBuffer mScratchMemoryBuffer;
unsigned int mScratchMemoryBufferResetCounter;
}; };
} }
......
...@@ -499,17 +499,19 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, Image *image, c ...@@ -499,17 +499,19 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, Image *image, c
UINT bufferRowPitch = outputPixelSize * width; UINT bufferRowPitch = outputPixelSize * width;
UINT bufferDepthPitch = bufferRowPitch * height; UINT bufferDepthPitch = bufferRowPitch * height;
MemoryBuffer conversionBuffer; size_t neededSize = bufferDepthPitch * depth;
if (!conversionBuffer.resize(bufferDepthPitch * depth)) MemoryBuffer *conversionBuffer = NULL;
error = mRenderer->getScratchMemoryBuffer(neededSize, &conversionBuffer);
if (error.isError())
{ {
return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); return error;
} }
// TODO: fast path // TODO: fast path
LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type); LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type);
loadFunction(width, height, depth, loadFunction(width, height, depth,
pixelData, srcRowPitch, srcDepthPitch, pixelData, srcRowPitch, srcDepthPitch,
conversionBuffer.data(), bufferRowPitch, bufferDepthPitch); conversionBuffer->data(), bufferRowPitch, bufferDepthPitch);
ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
...@@ -526,13 +528,13 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, Image *image, c ...@@ -526,13 +528,13 @@ gl::Error TextureStorage11::setData(const gl::ImageIndex &index, Image *image, c
destD3DBox.back = 1; destD3DBox.back = 1;
immediateContext->UpdateSubresource(resource, destSubresource, immediateContext->UpdateSubresource(resource, destSubresource,
&destD3DBox, conversionBuffer.data(), &destD3DBox, conversionBuffer->data(),
bufferRowPitch, bufferDepthPitch); bufferRowPitch, bufferDepthPitch);
} }
else else
{ {
immediateContext->UpdateSubresource(resource, destSubresource, immediateContext->UpdateSubresource(resource, destSubresource,
NULL, conversionBuffer.data(), NULL, conversionBuffer->data(),
bufferRowPitch, bufferDepthPitch); bufferRowPitch, bufferDepthPitch);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment