Chromium Code Reviews| Index: third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp |
| diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp |
| index 318f736275a6bf75ab5f87817a84479e61da748a..f04e2d6c9d62b806602fc08a830adf0abcbde2be 100644 |
| --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp |
| +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp |
| @@ -5,11 +5,13 @@ |
| #include "modules/webgl/WebGL2RenderingContextBase.h" |
| #include "bindings/modules/v8/WebGLAny.h" |
| +#include "core/dom/DOMException.h" |
| #include "core/frame/ImageBitmap.h" |
| #include "core/html/HTMLCanvasElement.h" |
| #include "core/html/HTMLImageElement.h" |
| #include "core/html/HTMLVideoElement.h" |
| #include "core/html/ImageData.h" |
| +#include "gpu/GLES2/gl2extchromium.h" |
| #include "gpu/command_buffer/client/gles2_interface.h" |
| #include "modules/webgl/WebGLActiveInfo.h" |
| #include "modules/webgl/WebGLBuffer.h" |
| @@ -187,6 +189,15 @@ WebGL2RenderingContextBase::~WebGL2RenderingContextBase() { |
| m_currentTransformFeedbackPrimitivesWrittenQuery = nullptr; |
| } |
| +void WebGL2RenderingContextBase::destroyContext() { |
| + for (auto& callback : m_getBufferSubDataAsyncCallbacks) { |
| + callback->destroy(); |
| + } |
| + m_getBufferSubDataAsyncCallbacks.clear(); |
| + |
| + WebGLRenderingContextBase::destroyContext(); |
| +} |
| + |
| void WebGL2RenderingContextBase::initializeNewContext() { |
| ASSERT(!isContextLost()); |
| ASSERT(drawingBuffer()); |
| @@ -386,6 +397,161 @@ void WebGL2RenderingContextBase::getBufferSubData(GLenum target, |
| contextGL()->UnmapBuffer(target); |
| } |
| +WebGL2RenderingContextBase::GetBufferSubDataAsyncCallback:: |
| + GetBufferSubDataAsyncCallback(WebGL2RenderingContextBase* context, |
| + DOMArrayBufferView* dstData, |
| + ScriptPromiseResolver* resolver, |
| + void* subBaseAddress, |
| + void* mappedData, |
| + long long subByteLength) |
| + : context(context), |
| + dstData(dstData), |
| + resolver(resolver), |
| + subBaseAddress(subBaseAddress), |
| + mappedData(mappedData), |
| + subByteLength(subByteLength) {} |
| + |
| +void WebGL2RenderingContextBase::GetBufferSubDataAsyncCallback::destroy() { |
| + context->contextGL()->FreeSharedMemory(mappedData); |
| + mappedData = nullptr; |
| + DOMException* exception = |
| + DOMException::create(InvalidStateError, "context lost or destroyed"); |
| + this->resolver->reject(exception); |
| +} |
| + |
| +void WebGL2RenderingContextBase::GetBufferSubDataAsyncCallback::resolve( |
| + GetBufferSubDataAsyncCallback* self) { |
| + if (!self->context || !self->mappedData) { |
| + DOMException* exception = |
| + DOMException::create(InvalidStateError, "context lost or destroyed"); |
| + self->resolver->reject(exception); |
| + return; |
| + } |
| + if (self->dstData->buffer()->isNeutered()) { |
| + // XXX: should this set a GL error? No, according to current spec draft. |
| + DOMException* exception = DOMException::create( |
| + InvalidStateError, "ArrayBufferView became invalid asynchronously"); |
| + self->resolver->reject(exception); |
| + return; |
| + } |
| + memcpy(self->subBaseAddress, self->mappedData, self->subByteLength); |
| + // XXX: What would happen if the DOM was suspended when the promise |
| + // became resolved? Could another JS task happen between the memcpy |
| + // and the promise resolution task? |
| + self->resolver->resolve(self->dstData); |
|
adamk
2016/10/07 23:00:43
My knowledge of the Blink event loop is a little r
yhirano
2016/10/12 09:32:02
When the window is suspended, ScriptPromiseResolve
tyoshino (SeeGerritForStatus)
2016/10/12 10:00:39
As this looked related to promises, I asked yhiran
|
| + |
| + self->destroy(); |
| + self->context->unregisterGetBufferSubDataAsyncCallback(self); |
| +} |
| + |
| +ScriptPromise WebGL2RenderingContextBase::getBufferSubDataAsync( |
| + ScriptState* scriptState, |
| + GLenum target, |
| + GLintptr srcByteOffset, |
| + DOMArrayBufferView* dstData, |
| + GLuint dstOffset, |
| + GLuint length) { |
| + ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); |
| + ScriptPromise promise = resolver->promise(); |
| + |
| + const char* funcName = "getBufferSubDataAsync"; |
| + if (isContextLost()) { |
| + DOMException* exception = |
| + DOMException::create(InvalidStateError, "context lost"); |
| + resolver->reject(exception); |
| + return promise; |
| + } |
| + if (!validateValueFitNonNegInt32(funcName, "srcByteOffset", srcByteOffset)) { |
| + DOMException* exception = |
| + DOMException::create(InvalidStateError, "invalid value: srcByteOffset"); |
| + resolver->reject(exception); |
| + return promise; |
| + } |
| + if (target == GL_TRANSFORM_FEEDBACK_BUFFER && m_transformFeedbackBinding) { |
| + // XXX: is this restriction enforced in the original getBufferSubData? Does it need to be added there, or can it be removed here? |
| + synthesizeGLError(GL_INVALID_OPERATION, funcName, |
| + "targeted transform feedback buffer is bound"); |
| + DOMException* exception = DOMException::create( |
| + InvalidStateError, |
| + "invalid operation: targeted transform feedback buffer is bound"); |
| + resolver->reject(exception); |
| + return promise; |
| + } |
| + WebGLBuffer* buffer = validateBufferDataTarget(funcName, target); |
| + if (!buffer) { |
| + DOMException* exception = DOMException::create( |
| + InvalidStateError, "invalid operation: no buffer bound to target"); |
| + resolver->reject(exception); |
| + return promise; |
| + } |
| + |
| + void* subBaseAddress = nullptr; |
| + long long subByteLength = 0; |
| + if (!validateSubSourceAndGetData(dstData, dstOffset, length, &subBaseAddress, |
| + &subByteLength)) { |
| + synthesizeGLError(GL_INVALID_VALUE, funcName, |
| + "dstOffset and length out of bounds of dstData"); |
| + DOMException* exception = |
| + DOMException::create(InvalidStateError, |
| + "invalid value: dstOffset and length " |
| + "out of bounds of dstData"); |
| + resolver->reject(exception); |
| + return promise; |
| + } |
| + if (subByteLength == 0) { |
| + resolver->resolve(dstData); |
| + return promise; |
| + } |
| + |
| + CheckedNumeric<long long> dstEnd = subByteLength; |
| + dstEnd += srcByteOffset; |
| + if (!dstEnd.IsValid() || dstEnd.ValueOrDie() > buffer->getSize()) { |
| + synthesizeGLError( |
| + GL_INVALID_VALUE, funcName, |
| + "offset + numBytes would extend beyond the end of buffer"); |
| + DOMException* exception = |
| + DOMException::create(InvalidStateError, |
| + "invalid value: offset + numBytes would extend " |
| + "beyond the end of buffer"); |
| + resolver->reject(exception); |
| + return promise; |
| + } |
| + |
| + GLuint queryID; |
| + contextGL()->GenQueriesEXT(1, &queryID); |
| + contextGL()->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, queryID); |
| + void* mappedData = contextGL()->GetBufferSubDataAsyncCHROMIUM( |
| + target, srcByteOffset, subByteLength); |
| + if (!mappedData) { |
| + DOMException* exception = |
| + DOMException::create(InvalidStateError, "out of memory"); |
| + resolver->reject(exception); |
| + return promise; |
| + } |
| + contextGL()->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); |
| + |
| + auto callbackObject = adoptRef(new GetBufferSubDataAsyncCallback( |
| + this, dstData, resolver, subBaseAddress, mappedData, subByteLength)); |
| + registerGetBufferSubDataAsyncCallback(callbackObject.get()); |
| + auto callback = |
| + WTF::bind(&GetBufferSubDataAsyncCallback::resolve, callbackObject); |
| + drawingBuffer()->contextProvider()->signalQuery( |
| + queryID, convertToBaseCallback(std::move(callback))); |
| + contextGL()->DeleteQueriesEXT(1, &queryID); |
| + |
| + return promise; |
| +} |
| + |
| +void WebGL2RenderingContextBase::registerGetBufferSubDataAsyncCallback( |
| + GetBufferSubDataAsyncCallback* callback) { |
| + m_getBufferSubDataAsyncCallbacks.insert(callback); |
| +} |
| + |
| +void WebGL2RenderingContextBase::unregisterGetBufferSubDataAsyncCallback( |
| + GetBufferSubDataAsyncCallback* callback) { |
| + m_getBufferSubDataAsyncCallbacks.erase(callback); |
| +} |
| + |
| void WebGL2RenderingContextBase::blitFramebuffer(GLint srcX0, |
| GLint srcY0, |
| GLint srcX1, |