| Index: third_party/WebKit/Source/modules/webgl/WebGLGetBufferSubDataAsync.cpp
|
| diff --git a/third_party/WebKit/Source/modules/webgl/WebGLGetBufferSubDataAsync.cpp b/third_party/WebKit/Source/modules/webgl/WebGLGetBufferSubDataAsync.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cd3e21da419656a66613a4a983e2edf4d5aa3f9d
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/modules/webgl/WebGLGetBufferSubDataAsync.cpp
|
| @@ -0,0 +1,174 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "modules/webgl/WebGLGetBufferSubDataAsync.h"
|
| +
|
| +#include "core/dom/DOMException.h"
|
| +#include "gpu/GLES2/gl2extchromium.h"
|
| +#include "gpu/command_buffer/client/gles2_interface.h"
|
| +#include "modules/webgl/WebGL2RenderingContextBase.h"
|
| +
|
| +namespace blink {
|
| +
|
| +WebGLGetBufferSubDataAsync::WebGLGetBufferSubDataAsync(
|
| + WebGLRenderingContextBase* context)
|
| + : WebGLExtension(context) {}
|
| +
|
| +WebGLExtensionName WebGLGetBufferSubDataAsync::name() const {
|
| + return WebGLGetBufferSubDataAsyncName;
|
| +}
|
| +
|
| +WebGLGetBufferSubDataAsync* WebGLGetBufferSubDataAsync::create(
|
| + WebGLRenderingContextBase* context) {
|
| + return new WebGLGetBufferSubDataAsync(context);
|
| +}
|
| +
|
| +bool WebGLGetBufferSubDataAsync::supported(WebGLRenderingContextBase* context) {
|
| + return true;
|
| +}
|
| +
|
| +const char* WebGLGetBufferSubDataAsync::extensionName() {
|
| + return "WEBGL_get_buffer_sub_data_async";
|
| +}
|
| +
|
| +ScriptPromise WebGLGetBufferSubDataAsync::getBufferSubDataAsync(
|
| + ScriptState* scriptState,
|
| + GLenum target,
|
| + GLintptr srcByteOffset,
|
| + DOMArrayBufferView* dstData,
|
| + GLuint dstOffset,
|
| + GLuint length) {
|
| + ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
|
| + ScriptPromise promise = resolver->promise();
|
| +
|
| + WebGLExtensionScopedContext scoped(this);
|
| + if (scoped.isLost()) {
|
| + DOMException* exception =
|
| + DOMException::create(InvalidStateError, "context lost");
|
| + resolver->reject(exception);
|
| + return promise;
|
| + }
|
| +
|
| + WebGL2RenderingContextBase* context = nullptr;
|
| + {
|
| + WebGLRenderingContextBase* contextBase = scoped.context();
|
| + DCHECK_GE(contextBase->version(), 2u);
|
| + context = static_cast<WebGL2RenderingContextBase*>(contextBase);
|
| + }
|
| +
|
| + WebGLBuffer* sourceBuffer = nullptr;
|
| + void* destinationDataPtr = nullptr;
|
| + long long destinationByteLength = 0;
|
| + const char* message = context->validateGetBufferSubData(
|
| + __FUNCTION__, target, srcByteOffset, dstData, dstOffset, length,
|
| + &sourceBuffer, &destinationDataPtr, &destinationByteLength);
|
| + if (message) {
|
| + // If there was a GL error, it was already synthesized in
|
| + // validateGetBufferSubData, so it's not done here.
|
| + DOMException* exception = DOMException::create(InvalidStateError, message);
|
| + resolver->reject(exception);
|
| + return promise;
|
| + }
|
| +
|
| + message = context->validateGetBufferSubDataBounds(
|
| + __FUNCTION__, sourceBuffer, srcByteOffset, destinationByteLength);
|
| + if (message) {
|
| + // If there was a GL error, it was already synthesized in
|
| + // validateGetBufferSubDataBounds, so it's not done here.
|
| + DOMException* exception = DOMException::create(InvalidStateError, message);
|
| + resolver->reject(exception);
|
| + return promise;
|
| + }
|
| +
|
| + // If the length of the copy is zero, this is a no-op.
|
| + if (!destinationByteLength) {
|
| + resolver->resolve(dstData);
|
| + return promise;
|
| + }
|
| +
|
| + GLuint queryID;
|
| + context->contextGL()->GenQueriesEXT(1, &queryID);
|
| + context->contextGL()->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, queryID);
|
| + void* mappedData = context->contextGL()->GetBufferSubDataAsyncCHROMIUM(
|
| + target, srcByteOffset, destinationByteLength);
|
| + context->contextGL()->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
|
| + if (!mappedData) {
|
| + DOMException* exception =
|
| + DOMException::create(InvalidStateError, "Out of memory");
|
| + resolver->reject(exception);
|
| + return promise;
|
| + }
|
| +
|
| + auto callbackObject = new WebGLGetBufferSubDataAsyncCallback(
|
| + context, resolver, mappedData, queryID, dstData, destinationDataPtr,
|
| + destinationByteLength);
|
| + context->registerGetBufferSubDataAsyncCallback(callbackObject);
|
| + auto callback = WTF::bind(&WebGLGetBufferSubDataAsyncCallback::resolve,
|
| + wrapPersistent(callbackObject));
|
| + context->drawingBuffer()->contextProvider()->signalQuery(
|
| + queryID, convertToBaseCallback(std::move(callback)));
|
| +
|
| + return promise;
|
| +}
|
| +
|
| +WebGLGetBufferSubDataAsyncCallback::WebGLGetBufferSubDataAsyncCallback(
|
| + WebGL2RenderingContextBase* context,
|
| + ScriptPromiseResolver* promiseResolver,
|
| + void* shmReadbackResultData,
|
| + GLuint commandsIssuedQueryID,
|
| + DOMArrayBufferView* destinationArrayBufferView,
|
| + void* destinationDataPtr,
|
| + long long destinationByteLength)
|
| + : m_context(context),
|
| + m_promiseResolver(promiseResolver),
|
| + m_shmReadbackResultData(shmReadbackResultData),
|
| + m_commandsIssuedQueryID(commandsIssuedQueryID),
|
| + m_destinationArrayBufferView(destinationArrayBufferView),
|
| + m_destinationDataPtr(destinationDataPtr),
|
| + m_destinationByteLength(destinationByteLength) {
|
| + DCHECK(shmReadbackResultData);
|
| + DCHECK(destinationDataPtr);
|
| +}
|
| +
|
| +void WebGLGetBufferSubDataAsyncCallback::destroy() {
|
| + DCHECK(m_shmReadbackResultData);
|
| + m_context->contextGL()->FreeSharedMemory(m_shmReadbackResultData);
|
| + m_shmReadbackResultData = nullptr;
|
| + DOMException* exception =
|
| + DOMException::create(InvalidStateError, "Context lost or destroyed");
|
| + m_promiseResolver->reject(exception);
|
| +}
|
| +
|
| +void WebGLGetBufferSubDataAsyncCallback::resolve() {
|
| + if (!m_context || !m_shmReadbackResultData) {
|
| + DOMException* exception =
|
| + DOMException::create(InvalidStateError, "Context lost or destroyed");
|
| + m_promiseResolver->reject(exception);
|
| + return;
|
| + }
|
| + if (m_destinationArrayBufferView->buffer()->isNeutered()) {
|
| + DOMException* exception = DOMException::create(
|
| + InvalidStateError, "ArrayBufferView became invalid asynchronously");
|
| + m_promiseResolver->reject(exception);
|
| + return;
|
| + }
|
| + memcpy(m_destinationDataPtr, m_shmReadbackResultData,
|
| + m_destinationByteLength);
|
| + // TODO(kainino): 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, which would see the wrong data?
|
| + m_promiseResolver->resolve(m_destinationArrayBufferView);
|
| +
|
| + m_context->contextGL()->DeleteQueriesEXT(1, &m_commandsIssuedQueryID);
|
| + this->destroy();
|
| + m_context->unregisterGetBufferSubDataAsyncCallback(this);
|
| +}
|
| +
|
| +DEFINE_TRACE(WebGLGetBufferSubDataAsyncCallback) {
|
| + visitor->trace(m_context);
|
| + visitor->trace(m_promiseResolver);
|
| + visitor->trace(m_destinationArrayBufferView);
|
| +}
|
| +
|
| +} // namespace blink
|
|
|