Skip to content

Commit

Permalink
Bug 1533522 - Truncate Buffer/Texture on GL_OOM. r=lsalzman, a=RyanVM
Browse files Browse the repository at this point in the history
  • Loading branch information
kdashg authored and MrAlex94 committed Jul 9, 2019
1 parent b0803cd commit b705c80
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 175 deletions.
157 changes: 78 additions & 79 deletions dom/canvas/WebGLBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,106 +115,105 @@ WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usa
}
#endif

const void* uploadData = data;

UniqueBuffer newIndexCache;
if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER &&
mContext->mNeedsIndexValidation)
{
newIndexCache = malloc(size);
if (!newIndexCache) {
mContext->ErrorOutOfMemory("%s: Failed to alloc index cache.", funcName);
return;
}
memcpy(newIndexCache.get(), data, size);
uploadData = newIndexCache.get();
const void* uploadData = data;

UniqueBuffer newIndexCache;
if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER &&
mContext->mNeedsIndexValidation) {
newIndexCache = malloc(size);
if (!newIndexCache) {
mContext->ErrorOutOfMemory("%s: Failed to alloc index cache.", funcName);
return;
}
memcpy(newIndexCache.get(), data, size);
uploadData = newIndexCache.get();
}

const auto& gl = mContext->gl;
gl->MakeCurrent();
const ScopedLazyBind lazyBind(gl, target, this);

const bool sizeChanges = (size != ByteLength());
if (sizeChanges) {
mContext->InvalidateBufferFetching();

gl::GLContext::LocalErrorScope errorScope(*gl);
gl->fBufferData(target, size, uploadData, usage);
const auto error = errorScope.GetError();

if (error) {
MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY);
mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error);
return;
}
} else {
gl->fBufferData(target, size, uploadData, usage);
const auto& gl = mContext->gl;
const ScopedLazyBind lazyBind(gl, target, this);

const bool sizeChanges = (size != ByteLength());
if (sizeChanges) {
gl::GLContext::LocalErrorScope errorScope(*gl);
gl->fBufferData(target, size, uploadData, usage);
const auto error = errorScope.GetError();

if (error) {
MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY);
mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName,
error);

// Truncate
mByteLength = 0;
// mFetchInvalidator.InvalidateCaches();
mIndexCache = nullptr;
return;
}
} else {
gl->fBufferData(target, size, uploadData, usage);
}

mContext->OnDataAllocCall();
mContext->OnDataAllocCall();

mUsage = usage;
mByteLength = size;
mIndexCache = Move(newIndexCache);
mUsage = usage;
mByteLength = size;
mIndexCache = Move(newIndexCache);

if (mIndexCache) {
if (mIndexRanges.size()) {
mContext->GeneratePerfWarning("[%p] Invalidating %u ranges.", this,
uint32_t(mIndexRanges.size()));
mIndexRanges.clear();
}
if (mIndexCache) {
if (mIndexRanges.size()) {
mContext->GeneratePerfWarning("[%p] Invalidating %u ranges.", this,
uint32_t(mIndexRanges.size()));
mIndexRanges.clear();
}
}

}

void
WebGLBuffer::BufferSubData(GLenum target, size_t dstByteOffset, size_t dataLen,
const void* data) const
{
const char funcName[] = "bufferSubData";
void WebGLBuffer::BufferSubData(GLenum target, size_t dstByteOffset,
size_t dataLen, const void* data) const {
const char funcName[] = "bufferSubData";

if (!ValidateRange(funcName, dstByteOffset, dataLen))
return;
if (!ValidateRange(funcName, dstByteOffset, dataLen)) return;

if (!CheckedInt<GLintptr>(dataLen).isValid())
return mContext->ErrorOutOfMemory("%s: Size too large.", funcName);
if (!CheckedInt<GLintptr>(dataLen).isValid())
return mContext->ErrorOutOfMemory("%s: Size too large.", funcName);

////
////

const void* uploadData = data;
if (mIndexCache) {
const auto cachedDataBegin = (uint8_t*)mIndexCache.get() + dstByteOffset;
memcpy(cachedDataBegin, data, dataLen);
uploadData = cachedDataBegin;
const void* uploadData = data;
if (mIndexCache) {
const auto cachedDataBegin = (uint8_t*)mIndexCache.get() + dstByteOffset;
memcpy(cachedDataBegin, data, dataLen);
uploadData = cachedDataBegin;

InvalidateCacheRange(dstByteOffset, dataLen);
}
InvalidateCacheRange(dstByteOffset, dataLen);
}

////
////

const auto& gl = mContext->gl;
gl->MakeCurrent();
const ScopedLazyBind lazyBind(gl, target, this);
const auto& gl = mContext->gl;
const ScopedLazyBind lazyBind(gl, target, this);

gl->fBufferSubData(target, dstByteOffset, dataLen, uploadData);
gl->fBufferSubData(target, dstByteOffset, dataLen, uploadData);
}

bool
WebGLBuffer::ValidateRange(const char* funcName, size_t byteOffset, size_t byteLen) const
{
auto availLength = mByteLength;
if (byteOffset > availLength) {
mContext->ErrorInvalidValue("%s: Offset passes the end of the buffer.", funcName);
return false;
}
availLength -= byteOffset;
bool WebGLBuffer::ValidateRange(const char* funcName, size_t byteOffset,
size_t byteLen) const {
auto availLength = mByteLength;
if (byteOffset > availLength) {
mContext->ErrorInvalidValue("%s: Offset passes the end of the buffer.",
funcName);
return false;
}
availLength -= byteOffset;

if (byteLen > availLength) {
mContext->ErrorInvalidValue("%s: Offset+size passes the end of the buffer.",
funcName);
return false;
}
if (byteLen > availLength) {
mContext->ErrorInvalidValue("%s: Offset+size passes the end of the buffer.",
funcName);
return false;
}

return true;
return true;
}

////////////////////////////////////////
Expand Down
56 changes: 27 additions & 29 deletions dom/canvas/WebGLRenderbuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,39 +194,37 @@ WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
mContext->ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
" size.",
funcName);
return;
}

mContext->MakeContextCurrent();

if (!usage->maxSamplesKnown) {
const_cast<webgl::FormatUsageInfo*>(usage)->ResolveMaxSamples(mContext->gl);
}
MOZ_ASSERT(usage->maxSamplesKnown);

if (samples > usage->maxSamples) {
mContext->ErrorInvalidOperation("%s: `samples` is out of the valid range.", funcName);
return;
}

// Validation complete.

const GLenum error = DoRenderbufferStorage(samples, usage, width, height);
if (error) {
const char* errorName = mContext->ErrorName(error);
mContext->GenerateWarning("%s generated error %s", funcName, errorName);
return;
return;
}

// Validation complete.

const GLenum error = DoRenderbufferStorage(samples, usage, width, height);
if (error) {
const char* errorName = mContext->ErrorName(error);
mContext->GenerateWarning("%s generated error %s", funcName, errorName);
if (error != LOCAL_GL_OUT_OF_MEMORY) {
// Truncate.
mSamples = 0;
mFormat = nullptr;
mWidth = 0;
mHeight = 0;
mImageDataStatus = WebGLImageDataStatus::NoImageData;

InvalidateStatusOfAttachedFBs(funcName);
}
return;
}

mContext->OnDataAllocCall();
mContext->OnDataAllocCall();

mSamples = samples;
mFormat = usage;
mWidth = width;
mHeight = height;
mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
mSamples = samples;
mFormat = usage;
mWidth = width;
mHeight = height;
mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;

InvalidateStatusOfAttachedFBs(funcName);
InvalidateStatusOfAttachedFBs(funcName);
}

void
Expand Down

0 comments on commit b705c80

Please sign in to comment.