| Index: gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| index 1158858ee8546f29c249cc7d384770918a6f4f9c..b89024ed766e3b0311100ceb315c90cd1f152ece 100644
|
| --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| @@ -659,6 +659,18 @@ class GLES2DecoderImpl : public GLES2Decoder {
|
| return vertex_array_manager_.get();
|
| }
|
|
|
| + MemoryTracker* memory_tracker() {
|
| + return group_->memory_tracker();
|
| + }
|
| +
|
| + bool EnsureGPUMemoryAvailable(size_t estimated_size) {
|
| + MemoryTracker* tracker = memory_tracker();
|
| + if (tracker) {
|
| + return tracker->EnsureGPUMemoryAvailable(estimated_size);
|
| + }
|
| + return true;
|
| + }
|
| +
|
| bool IsOffscreenBufferMultisampled() const {
|
| return offscreen_target_samples_ > 1;
|
| }
|
| @@ -1826,8 +1838,7 @@ ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
|
|
|
| Texture::Texture(GLES2DecoderImpl* decoder)
|
| : decoder_(decoder),
|
| - memory_tracker_(decoder->GetContextGroup()->memory_tracker(),
|
| - MemoryTracker::kUnmanaged),
|
| + memory_tracker_(decoder->memory_tracker(), MemoryTracker::kUnmanaged),
|
| bytes_allocated_(0),
|
| id_(0) {
|
| }
|
| @@ -1862,8 +1873,7 @@ void Texture::Create() {
|
| memory_tracker_.TrackMemAlloc(bytes_allocated_);
|
| }
|
|
|
| -bool Texture::AllocateStorage(const gfx::Size& size, GLenum format,
|
| - bool zero) {
|
| +bool Texture::AllocateStorage(const gfx::Size& size, GLenum format, bool zero) {
|
| DCHECK_NE(id_, 0u);
|
| ScopedGLErrorSuppressor suppressor(decoder_);
|
| ScopedTexture2DBinder binder(decoder_, id_);
|
| @@ -1872,6 +1882,10 @@ bool Texture::AllocateStorage(const gfx::Size& size, GLenum format,
|
| size.width(), size.height(), format, GL_UNSIGNED_BYTE, 8, &image_size,
|
| NULL, NULL);
|
|
|
| + if (!memory_tracker_.EnsureGPUMemoryAvailable(image_size)) {
|
| + return false;
|
| + }
|
| +
|
| scoped_array<char> zero_data;
|
| if (zero) {
|
| zero_data.reset(new char[image_size]);
|
| @@ -1928,8 +1942,7 @@ void Texture::Invalidate() {
|
|
|
| RenderBuffer::RenderBuffer(GLES2DecoderImpl* decoder)
|
| : decoder_(decoder),
|
| - memory_tracker_(decoder->GetContextGroup()->memory_tracker(),
|
| - MemoryTracker::kUnmanaged),
|
| + memory_tracker_(decoder->memory_tracker(), MemoryTracker::kUnmanaged),
|
| bytes_allocated_(0),
|
| id_(0) {
|
| }
|
| @@ -1951,6 +1964,17 @@ bool RenderBuffer::AllocateStorage(const gfx::Size& size, GLenum format,
|
| GLsizei samples) {
|
| ScopedGLErrorSuppressor suppressor(decoder_);
|
| ScopedRenderBufferBinder binder(decoder_, id_);
|
| +
|
| + uint32 estimated_size = 0;
|
| + if (!RenderbufferManager::ComputeEstimatedRenderbufferSize(
|
| + size.width(), size.height(), samples, format, &estimated_size)) {
|
| + return false;
|
| + }
|
| +
|
| + if (!memory_tracker_.EnsureGPUMemoryAvailable(estimated_size)) {
|
| + return false;
|
| + }
|
| +
|
| if (samples <= 1) {
|
| glRenderbufferStorageEXT(GL_RENDERBUFFER,
|
| format,
|
| @@ -1974,9 +1998,7 @@ bool RenderBuffer::AllocateStorage(const gfx::Size& size, GLenum format,
|
| bool success = glGetError() == GL_NO_ERROR;
|
| if (success) {
|
| memory_tracker_.TrackMemFree(bytes_allocated_);
|
| - bytes_allocated_ =
|
| - size.width() * size.height() * samples *
|
| - GLES2Util::RenderbufferBytesPerPixel(format);
|
| + bytes_allocated_ = estimated_size;
|
| memory_tracker_.TrackMemAlloc(bytes_allocated_);
|
| }
|
| return success;
|
| @@ -4782,39 +4804,39 @@ void GLES2DecoderImpl::DoRenderbufferStorageMultisample(
|
| GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
|
| if (!renderbuffer) {
|
| SetGLError(GL_INVALID_OPERATION,
|
| - "glGetRenderbufferStorageMultisample", "no renderbuffer bound");
|
| + "glRenderbufferStorageMultisampleEXT", "no renderbuffer bound");
|
| return;
|
| }
|
|
|
| if (samples > renderbuffer_manager()->max_samples()) {
|
| SetGLError(GL_INVALID_VALUE,
|
| - "glGetRenderbufferStorageMultisample", "samples too large");
|
| + "glRenderbufferStorageMultisampleEXT", "samples too large");
|
| return;
|
| }
|
|
|
| if (width > renderbuffer_manager()->max_renderbuffer_size() ||
|
| height > renderbuffer_manager()->max_renderbuffer_size()) {
|
| SetGLError(GL_INVALID_VALUE,
|
| - "glGetRenderbufferStorageMultisample", "size too large");
|
| + "glRenderbufferStorageMultisample", "dimensions too large");
|
| return;
|
| }
|
|
|
| - GLenum impl_format = internalformat;
|
| - if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
|
| - switch (impl_format) {
|
| - case GL_DEPTH_COMPONENT16:
|
| - impl_format = GL_DEPTH_COMPONENT;
|
| - break;
|
| - case GL_RGBA4:
|
| - case GL_RGB5_A1:
|
| - impl_format = GL_RGBA;
|
| - break;
|
| - case GL_RGB565:
|
| - impl_format = GL_RGB;
|
| - break;
|
| - }
|
| + uint32 estimated_size = 0;
|
| + if (!RenderbufferManager::ComputeEstimatedRenderbufferSize(
|
| + width, height, samples, internalformat, &estimated_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY,
|
| + "glRenderbufferStorageMultsampleEXT", "dimensions too large");
|
| + return;
|
| }
|
|
|
| + if (!EnsureGPUMemoryAvailable(estimated_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY,
|
| + "glRenderbufferStorageMultsampleEXT", "out of memory");
|
| + return;
|
| + }
|
| +
|
| + GLenum impl_format = RenderbufferManager::
|
| + InternalRenderbufferFormatToImplFormat(internalformat);
|
| CopyRealGLErrorsToWrapper();
|
| if (IsAngle()) {
|
| glRenderbufferStorageMultisampleANGLE(
|
| @@ -4839,42 +4861,42 @@ void GLES2DecoderImpl::DoRenderbufferStorage(
|
| GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
|
| if (!renderbuffer) {
|
| SetGLError(GL_INVALID_OPERATION,
|
| - "glGetRenderbufferStorage", "no renderbuffer bound");
|
| + "glRenderbufferStorage", "no renderbuffer bound");
|
| return;
|
| }
|
|
|
| if (width > renderbuffer_manager()->max_renderbuffer_size() ||
|
| height > renderbuffer_manager()->max_renderbuffer_size()) {
|
| SetGLError(GL_INVALID_VALUE,
|
| - "glGetRenderbufferStorage", "size too large");
|
| + "glRenderbufferStorage", "dimensions too large");
|
| return;
|
| }
|
|
|
| - GLenum impl_format = internalformat;
|
| - if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
|
| - switch (impl_format) {
|
| - case GL_DEPTH_COMPONENT16:
|
| - impl_format = GL_DEPTH_COMPONENT;
|
| - break;
|
| - case GL_RGBA4:
|
| - case GL_RGB5_A1:
|
| - impl_format = GL_RGBA;
|
| - break;
|
| - case GL_RGB565:
|
| - impl_format = GL_RGB;
|
| - break;
|
| - }
|
| + uint32 estimated_size = 0;
|
| + if (!RenderbufferManager::ComputeEstimatedRenderbufferSize(
|
| + width, height, 1, internalformat, &estimated_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glRenderbufferStorage",
|
| + "dimensions too large");
|
| + return;
|
| + }
|
| +
|
| + if (!EnsureGPUMemoryAvailable(estimated_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glRenderbufferStorage", "out of memory");
|
| + return;
|
| }
|
|
|
| CopyRealGLErrorsToWrapper();
|
| - glRenderbufferStorageEXT(target, impl_format, width, height);
|
| + glRenderbufferStorageEXT(
|
| + target, RenderbufferManager::
|
| + InternalRenderbufferFormatToImplFormat(internalformat),
|
| + width, height);
|
| GLenum error = PeekGLError();
|
| if (error == GL_NO_ERROR) {
|
| // TODO(gman): If tetxures tracked which framebuffers they were attached to
|
| // we could just mark those framebuffers as not complete.
|
| framebuffer_manager()->IncFramebufferStateChangeCount();
|
| renderbuffer_manager()->SetInfo(
|
| - renderbuffer, 0, internalformat, width, height);
|
| + renderbuffer, 1, internalformat, width, height);
|
| }
|
| }
|
|
|
| @@ -7091,6 +7113,12 @@ void GLES2DecoderImpl::DoBufferData(
|
| SetGLError(GL_INVALID_VALUE, "glBufferData", "unknown buffer");
|
| return;
|
| }
|
| +
|
| + if (!EnsureGPUMemoryAvailable(size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glBufferData", "out of memory");
|
| + return;
|
| + }
|
| +
|
| // Clear the buffer to 0 if no initial data was passed in.
|
| scoped_array<int8> zero;
|
| if (!data) {
|
| @@ -7442,6 +7470,11 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage2D(
|
| return error::kNoError;
|
| }
|
|
|
| + if (!EnsureGPUMemoryAvailable(image_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glCompressedTexImage2D", "out of memory");
|
| + return error::kNoError;
|
| + }
|
| +
|
| if (info->IsAttachedToFramebuffer()) {
|
| clear_state_dirty_ = true;
|
| // TODO(gman): If textures tracked which framebuffers they were attached to
|
| @@ -7676,6 +7709,12 @@ void GLES2DecoderImpl::DoTexImage2D(
|
| width, height, border, format, type, pixels, pixels_size)) {
|
| return;
|
| }
|
| +
|
| + if (!EnsureGPUMemoryAvailable(pixels_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
|
| + return;
|
| + }
|
| +
|
| TextureManager::TextureInfo* info = GetTextureInfoForTarget(target);
|
| GLsizei tex_width = 0;
|
| GLsizei tex_height = 0;
|
| @@ -7902,7 +7941,20 @@ void GLES2DecoderImpl::DoCopyTexImage2D(
|
| if ((channels_needed & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0) {
|
| SetGLError(
|
| GL_INVALID_OPERATION,
|
| - "glCopyImage2D", "can not be used with depth or stencil textures");
|
| + "glCopyTexImage2D", "can not be used with depth or stencil textures");
|
| + return;
|
| + }
|
| +
|
| + uint32 estimated_size = 0;
|
| + if (!GLES2Util::ComputeImageDataSizes(
|
| + width, height, internal_format, GL_UNSIGNED_BYTE, state_.unpack_alignment,
|
| + &estimated_size, NULL, NULL)) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glCopyTexImage2D", "dimensions too large");
|
| + return;
|
| + }
|
| +
|
| + if (!EnsureGPUMemoryAvailable(estimated_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glCopyTexImage2D", "out of memory");
|
| return;
|
| }
|
|
|
| @@ -9575,13 +9627,38 @@ void GLES2DecoderImpl::DoTexStorage2DEXT(
|
| "glTexStorage2DEXT", "texture is immutable");
|
| return;
|
| }
|
| +
|
| + GLenum format = ExtractFormatFromStorageFormat(internal_format);
|
| + GLenum type = ExtractTypeFromStorageFormat(internal_format);
|
| +
|
| + {
|
| + GLsizei level_width = width;
|
| + GLsizei level_height = height;
|
| + uint32 estimated_size = 0;
|
| + for (int ii = 0; ii < levels; ++ii) {
|
| + uint32 level_size = 0;
|
| + if (!GLES2Util::ComputeImageDataSizes(
|
| + level_width, level_height, format, type, state_.unpack_alignment,
|
| + &estimated_size, NULL, NULL) ||
|
| + !SafeAddUint32(estimated_size, level_size, &estimated_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY,
|
| + "glTexStorage2DEXT", "dimensions too large");
|
| + return;
|
| + }
|
| + level_width = std::max(1, level_width >> 1);
|
| + level_height = std::max(1, level_height >> 1);
|
| + }
|
| + if (!EnsureGPUMemoryAvailable(estimated_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glTexStorage2DEXT", "out of memory");
|
| + return;
|
| + }
|
| + }
|
| +
|
| CopyRealGLErrorsToWrapper();
|
| glTexStorage2DEXT(target, levels, GetTexInternalFormat(internal_format),
|
| width, height);
|
| GLenum error = PeekGLError();
|
| if (error == GL_NO_ERROR) {
|
| - GLenum format = ExtractFormatFromStorageFormat(internal_format);
|
| - GLenum type = ExtractTypeFromStorageFormat(internal_format);
|
| GLsizei level_width = width;
|
| GLsizei level_height = height;
|
| for (int ii = 0; ii < levels; ++ii) {
|
| @@ -9883,6 +9960,11 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
|
| return error::kNoError;
|
| }
|
|
|
| + if (!EnsureGPUMemoryAvailable(pixels_size)) {
|
| + SetGLError(GL_OUT_OF_MEMORY, "glAsyncTexImage2DCHROMIUM", "out of memory");
|
| + return error::kNoError;
|
| + }
|
| +
|
| // We know the memory/size is safe, so get the real shared memory since
|
| // it might need to be duped to prevent use-after-free of the memory.
|
| Buffer buffer = GetSharedMemoryBuffer(c.pixels_shm_id);
|
|
|