Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp

Issue 2379203002: implement getBufferSubDataAsync prototype (Closed)
Patch Set: factor out common validation code from getBufferSubData/Async Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "modules/webgl/WebGL2RenderingContextBase.h" 5 #include "modules/webgl/WebGL2RenderingContextBase.h"
6 6
7 #include "bindings/modules/v8/WebGLAny.h" 7 #include "bindings/modules/v8/WebGLAny.h"
8 #include "core/dom/DOMException.h"
8 #include "core/frame/ImageBitmap.h" 9 #include "core/frame/ImageBitmap.h"
9 #include "core/html/HTMLCanvasElement.h" 10 #include "core/html/HTMLCanvasElement.h"
10 #include "core/html/HTMLImageElement.h" 11 #include "core/html/HTMLImageElement.h"
11 #include "core/html/HTMLVideoElement.h" 12 #include "core/html/HTMLVideoElement.h"
12 #include "core/html/ImageData.h" 13 #include "core/html/ImageData.h"
14 #include "gpu/GLES2/gl2extchromium.h"
13 #include "gpu/command_buffer/client/gles2_interface.h" 15 #include "gpu/command_buffer/client/gles2_interface.h"
14 #include "modules/webgl/WebGLActiveInfo.h" 16 #include "modules/webgl/WebGLActiveInfo.h"
15 #include "modules/webgl/WebGLBuffer.h" 17 #include "modules/webgl/WebGLBuffer.h"
16 #include "modules/webgl/WebGLFenceSync.h" 18 #include "modules/webgl/WebGLFenceSync.h"
17 #include "modules/webgl/WebGLFramebuffer.h" 19 #include "modules/webgl/WebGLFramebuffer.h"
18 #include "modules/webgl/WebGLProgram.h" 20 #include "modules/webgl/WebGLProgram.h"
19 #include "modules/webgl/WebGLQuery.h" 21 #include "modules/webgl/WebGLQuery.h"
20 #include "modules/webgl/WebGLRenderbuffer.h" 22 #include "modules/webgl/WebGLRenderbuffer.h"
21 #include "modules/webgl/WebGLSampler.h" 23 #include "modules/webgl/WebGLSampler.h"
22 #include "modules/webgl/WebGLSync.h" 24 #include "modules/webgl/WebGLSync.h"
(...skipping 10 matching lines...) Expand all
33 using WTF::String; 35 using WTF::String;
34 36
35 namespace blink { 37 namespace blink {
36 38
37 namespace { 39 namespace {
38 40
39 GLsync syncObjectOrZero(const WebGLSync* object) { 41 GLsync syncObjectOrZero(const WebGLSync* object) {
40 return object ? object->object() : nullptr; 42 return object ? object->object() : nullptr;
41 } 43 }
42 44
45 // TODO(kainino): Change outByteLength to GLuint and change the associated
46 // range checking (and all uses) - overflow becomes possible in cases below
43 bool validateSubSourceAndGetData(DOMArrayBufferView* view, 47 bool validateSubSourceAndGetData(DOMArrayBufferView* view,
44 GLuint subOffset, 48 GLuint subOffset,
45 GLuint subLength, 49 GLuint subLength,
46 void** outBaseAddress, 50 void** outBaseAddress,
47 long long* outByteLength) { 51 long long* outByteLength) {
48 // This is guaranteed to be non-null by DOM. 52 // This is guaranteed to be non-null by DOM.
49 DCHECK(view); 53 DCHECK(view);
50 54
51 size_t typeSize = view->typeSize(); 55 size_t typeSize = view->typeSize();
52 DCHECK_GE(8u, typeSize); 56 DCHECK_GE(8u, typeSize);
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 GL_COMPRESSED_RG11_EAC, 145 GL_COMPRESSED_RG11_EAC,
142 GL_COMPRESSED_SIGNED_RG11_EAC, 146 GL_COMPRESSED_SIGNED_RG11_EAC,
143 GL_COMPRESSED_RGB8_ETC2, 147 GL_COMPRESSED_RGB8_ETC2,
144 GL_COMPRESSED_SRGB8_ETC2, 148 GL_COMPRESSED_SRGB8_ETC2,
145 GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, 149 GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
146 GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, 150 GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
147 GL_COMPRESSED_RGBA8_ETC2_EAC, 151 GL_COMPRESSED_RGBA8_ETC2_EAC,
148 GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, 152 GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
149 }; 153 };
150 154
155 class WebGLGetBufferSubDataAsyncCallback
156 : public RefCounted<WebGLGetBufferSubDataAsyncCallback> {
157 public:
158 WebGLGetBufferSubDataAsyncCallback(
159 WebGL2RenderingContextBase* context,
160 ScriptPromiseResolver* promiseResolver,
161 void* shmReadbackResultData,
162 GLuint commandsIssuedQueryID,
163 DOMArrayBufferView* destinationArrayBufferView,
164 void* destinationDataPtr,
165 long long destinationByteLength)
166 : context(context),
167 promiseResolver(promiseResolver),
168 shmReadbackResultData(shmReadbackResultData),
169 commandsIssuedQueryID(commandsIssuedQueryID),
170 destinationArrayBufferView(destinationArrayBufferView),
171 destinationDataPtr(destinationDataPtr),
172 destinationByteLength(destinationByteLength) {
173 DCHECK(shmReadbackResultData);
174 DCHECK(destinationDataPtr);
175 }
176
177 void destroy() {
178 DCHECK(shmReadbackResultData);
179 context->contextGL()->FreeSharedMemory(shmReadbackResultData);
180 shmReadbackResultData = nullptr;
181 DOMException* exception =
182 DOMException::create(InvalidStateError, "Context lost or destroyed");
183 this->promiseResolver->reject(exception);
184 }
185
186 void resolve() {
187 if (!this->context || !this->shmReadbackResultData) {
188 DOMException* exception =
189 DOMException::create(InvalidStateError, "Context lost or destroyed");
190 this->promiseResolver->reject(exception);
191 return;
192 }
193 if (this->destinationArrayBufferView->buffer()->isNeutered()) {
194 DOMException* exception = DOMException::create(
195 InvalidStateError, "ArrayBufferView became invalid asynchronously");
196 this->promiseResolver->reject(exception);
197 return;
198 }
199 memcpy(this->destinationDataPtr, this->shmReadbackResultData,
200 this->destinationByteLength);
201 // XXX: What would happen if the DOM was suspended when the promise
Ken Russell (switch to Gerrit) 2016/10/11 22:31:16 Still needs to be addressed. OK to leave as a TODO
Kai Ninomiya 2016/10/11 22:42:35 Done. This is on my personal TODO for this project
202 // became resolved? Could another JS task happen between the memcpy
203 // and the promise resolution task?
204 this->promiseResolver->resolve(this->destinationArrayBufferView);
205
206 context->contextGL()->DeleteQueriesEXT(1, &commandsIssuedQueryID);
207 this->destroy();
208 this->context->unregisterGetBufferSubDataAsyncCallback(this);
209 }
210
211 private:
212 WeakPersistent<WebGL2RenderingContextBase> context;
213 Persistent<ScriptPromiseResolver> promiseResolver;
214
215 // Pointer to shared memory where the gpu readback result is stored.
216 void* shmReadbackResultData;
217 // ID of the GL query used to call this callback.
218 GLuint commandsIssuedQueryID;
219
220 // ArrayBufferView returned from the promise.
221 Persistent<DOMArrayBufferView> destinationArrayBufferView;
222 // Pointer into the offset into destinationArrayBufferView
Ken Russell (switch to Gerrit) 2016/10/11 22:31:16 Add ".".
Kai Ninomiya 2016/10/11 22:42:35 Done.
223 void* destinationDataPtr;
224 // Size in bytes of the copy operation being performed.
225 long long destinationByteLength;
226 };
227
151 WebGL2RenderingContextBase::WebGL2RenderingContextBase( 228 WebGL2RenderingContextBase::WebGL2RenderingContextBase(
152 HTMLCanvasElement* passedCanvas, 229 HTMLCanvasElement* passedCanvas,
153 std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, 230 std::unique_ptr<WebGraphicsContext3DProvider> contextProvider,
154 const CanvasContextCreationAttributes& requestedAttributes) 231 const CanvasContextCreationAttributes& requestedAttributes)
155 : WebGLRenderingContextBase(passedCanvas, 232 : WebGLRenderingContextBase(passedCanvas,
156 std::move(contextProvider), 233 std::move(contextProvider),
157 requestedAttributes, 234 requestedAttributes,
158 2) { 235 2) {
159 m_supportedInternalFormatsStorage.insert( 236 m_supportedInternalFormatsStorage.insert(
160 kSupportedInternalFormatsStorage, 237 kSupportedInternalFormatsStorage,
(...skipping 19 matching lines...) Expand all
180 m_boundCopyWriteBuffer = nullptr; 257 m_boundCopyWriteBuffer = nullptr;
181 m_boundPixelPackBuffer = nullptr; 258 m_boundPixelPackBuffer = nullptr;
182 m_boundPixelUnpackBuffer = nullptr; 259 m_boundPixelUnpackBuffer = nullptr;
183 m_boundTransformFeedbackBuffer = nullptr; 260 m_boundTransformFeedbackBuffer = nullptr;
184 m_boundUniformBuffer = nullptr; 261 m_boundUniformBuffer = nullptr;
185 262
186 m_currentBooleanOcclusionQuery = nullptr; 263 m_currentBooleanOcclusionQuery = nullptr;
187 m_currentTransformFeedbackPrimitivesWrittenQuery = nullptr; 264 m_currentTransformFeedbackPrimitivesWrittenQuery = nullptr;
188 } 265 }
189 266
267 void WebGL2RenderingContextBase::destroyContext() {
268 for (auto& callback : m_getBufferSubDataAsyncCallbacks) {
269 callback->destroy();
270 }
271 m_getBufferSubDataAsyncCallbacks.clear();
272
273 WebGLRenderingContextBase::destroyContext();
274 }
275
190 void WebGL2RenderingContextBase::initializeNewContext() { 276 void WebGL2RenderingContextBase::initializeNewContext() {
191 ASSERT(!isContextLost()); 277 ASSERT(!isContextLost());
192 ASSERT(drawingBuffer()); 278 ASSERT(drawingBuffer());
193 279
194 m_readFramebufferBinding = nullptr; 280 m_readFramebufferBinding = nullptr;
195 281
196 m_boundCopyReadBuffer = nullptr; 282 m_boundCopyReadBuffer = nullptr;
197 m_boundCopyWriteBuffer = nullptr; 283 m_boundCopyWriteBuffer = nullptr;
198 m_boundPixelPackBuffer = nullptr; 284 m_boundPixelPackBuffer = nullptr;
199 m_boundPixelUnpackBuffer = nullptr; 285 m_boundPixelUnpackBuffer = nullptr;
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 contextGL()->CopyBufferSubData( 436 contextGL()->CopyBufferSubData(
351 readTarget, writeTarget, static_cast<GLintptr>(readOffset), 437 readTarget, writeTarget, static_cast<GLintptr>(readOffset),
352 static_cast<GLintptr>(writeOffset), static_cast<GLsizeiptr>(size)); 438 static_cast<GLintptr>(writeOffset), static_cast<GLsizeiptr>(size));
353 } 439 }
354 440
355 void WebGL2RenderingContextBase::getBufferSubData(GLenum target, 441 void WebGL2RenderingContextBase::getBufferSubData(GLenum target,
356 long long srcByteOffset, 442 long long srcByteOffset,
357 DOMArrayBufferView* dstData, 443 DOMArrayBufferView* dstData,
358 GLuint dstOffset, 444 GLuint dstOffset,
359 GLuint length) { 445 GLuint length) {
360 const char* funcName = "getBufferSubData"; 446 WebGLBuffer* sourceBuffer = nullptr;
361 if (isContextLost()) 447 void* destinationDataPtr = nullptr;
362 return; 448 long long destinationByteLength = 0;
363 if (!validateValueFitNonNegInt32(funcName, "srcByteOffset", srcByteOffset)) { 449 const char* message = validateGetBufferSubData(
450 __FUNCTION__, target, srcByteOffset, dstData, dstOffset, length,
451 &sourceBuffer, &destinationDataPtr, &destinationByteLength);
452 if (message) {
364 return; 453 return;
365 } 454 }
366 WebGLBuffer* buffer = validateBufferDataTarget(funcName, target); 455
367 if (!buffer) 456 // If the length of the copy is zero, this is a no-op
Ken Russell (switch to Gerrit) 2016/10/11 22:31:16 Add ".".
Kai Ninomiya 2016/10/11 22:42:35 Done.
368 return; 457 if (!destinationByteLength) {
369 void* subBaseAddress = nullptr;
370 long long subByteLength = 0;
371 if (!validateSubSourceAndGetData(dstData, dstOffset, length, &subBaseAddress,
372 &subByteLength)) {
373 synthesizeGLError(GL_INVALID_VALUE, funcName, "buffer overflow");
374 return;
375 }
376 if (subByteLength == 0) {
377 return; 458 return;
378 } 459 }
379 460
380 void* mappedData = 461 void* mappedData =
381 contextGL()->MapBufferRange(target, static_cast<GLintptr>(srcByteOffset), 462 contextGL()->MapBufferRange(target, static_cast<GLintptr>(srcByteOffset),
382 subByteLength, GL_MAP_READ_BIT); 463 destinationByteLength, GL_MAP_READ_BIT);
383 464
384 if (!mappedData) 465 if (!mappedData)
385 return; 466 return;
386 467
387 memcpy(subBaseAddress, mappedData, subByteLength); 468 memcpy(destinationDataPtr, mappedData, destinationByteLength);
388 469
389 contextGL()->UnmapBuffer(target); 470 contextGL()->UnmapBuffer(target);
390 } 471 }
391 472
473 ScriptPromise WebGL2RenderingContextBase::getBufferSubDataAsync(
474 ScriptState* scriptState,
475 GLenum target,
476 GLintptr srcByteOffset,
477 DOMArrayBufferView* dstData,
478 GLuint dstOffset,
479 GLuint length) {
480 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
481 ScriptPromise promise = resolver->promise();
482
483 WebGLBuffer* sourceBuffer = nullptr;
484 void* destinationDataPtr = nullptr;
485 long long destinationByteLength = 0;
486 const char* message = validateGetBufferSubData(
487 __FUNCTION__, target, srcByteOffset, dstData, dstOffset, length,
488 &sourceBuffer, &destinationDataPtr, &destinationByteLength);
489 if (message) {
490 DOMException* exception = DOMException::create(InvalidStateError, message);
491 resolver->reject(exception);
492 return promise;
493 }
494
495 message = validateGetBufferSubDataBounds(
496 __FUNCTION__, sourceBuffer, srcByteOffset, destinationByteLength);
497 if (message) {
498 DOMException* exception = DOMException::create(InvalidStateError, message);
499 resolver->reject(exception);
500 return promise;
501 }
502
503 // If the length of the copy is zero, this is a no-op
Ken Russell (switch to Gerrit) 2016/10/11 22:31:16 Add ".".
Kai Ninomiya 2016/10/11 22:42:35 Done.
504 if (!destinationByteLength) {
505 resolver->resolve(dstData);
506 return promise;
507 }
508
509 GLuint queryID;
510 contextGL()->GenQueriesEXT(1, &queryID);
511 contextGL()->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, queryID);
512 void* mappedData = contextGL()->GetBufferSubDataAsyncCHROMIUM(
513 target, srcByteOffset, destinationByteLength);
514 contextGL()->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
515 if (!mappedData) {
516 DOMException* exception =
517 DOMException::create(InvalidStateError, "Out of memory");
518 resolver->reject(exception);
519 return promise;
520 }
521
522 auto callbackObject = adoptRef(new WebGLGetBufferSubDataAsyncCallback(
523 this, resolver, mappedData, queryID, dstData, destinationDataPtr,
524 destinationByteLength));
525 registerGetBufferSubDataAsyncCallback(callbackObject.get());
526 auto callback =
527 WTF::bind(&WebGLGetBufferSubDataAsyncCallback::resolve, callbackObject);
528 drawingBuffer()->contextProvider()->signalQuery(
529 queryID, convertToBaseCallback(std::move(callback)));
530
531 return promise;
532 }
533
534 void WebGL2RenderingContextBase::registerGetBufferSubDataAsyncCallback(
535 WebGLGetBufferSubDataAsyncCallback* callback) {
536 m_getBufferSubDataAsyncCallbacks.insert(callback);
537 }
538
539 void WebGL2RenderingContextBase::unregisterGetBufferSubDataAsyncCallback(
540 WebGLGetBufferSubDataAsyncCallback* callback) {
541 m_getBufferSubDataAsyncCallbacks.erase(callback);
542 }
543
392 void WebGL2RenderingContextBase::blitFramebuffer(GLint srcX0, 544 void WebGL2RenderingContextBase::blitFramebuffer(GLint srcX0,
393 GLint srcY0, 545 GLint srcY0,
394 GLint srcX1, 546 GLint srcX1,
395 GLint srcY1, 547 GLint srcY1,
396 GLint dstX0, 548 GLint dstX0,
397 GLint dstY0, 549 GLint dstY0,
398 GLint dstX1, 550 GLint dstX1,
399 GLint dstY1, 551 GLint dstY1,
400 GLbitfield mask, 552 GLbitfield mask,
401 GLenum filter) { 553 GLenum filter) {
(...skipping 4010 matching lines...) Expand 10 before | Expand all | Expand 10 after
4412 case GL_STATIC_COPY: 4564 case GL_STATIC_COPY:
4413 case GL_DYNAMIC_READ: 4565 case GL_DYNAMIC_READ:
4414 case GL_DYNAMIC_COPY: 4566 case GL_DYNAMIC_COPY:
4415 return true; 4567 return true;
4416 default: 4568 default:
4417 return WebGLRenderingContextBase::validateBufferDataUsage(functionName, 4569 return WebGLRenderingContextBase::validateBufferDataUsage(functionName,
4418 usage); 4570 usage);
4419 } 4571 }
4420 } 4572 }
4421 4573
4574 const char* WebGL2RenderingContextBase::validateGetBufferSubData(
4575 const char* functionName,
4576 GLenum target,
4577 GLintptr sourceByteOffset,
4578 DOMArrayBufferView* destinationArrayBufferView,
4579 GLuint destinationOffset,
4580 GLuint length,
4581 WebGLBuffer** outSourceBuffer,
4582 void** outDestinationDataPtr,
4583 long long* outDestinationByteLength) {
4584 if (isContextLost()) {
4585 return "Context lost";
4586 }
4587
4588 if (!validateValueFitNonNegInt32(functionName, "srcByteOffset",
4589 sourceByteOffset)) {
4590 return "Invalid value: srcByteOffset";
4591 }
4592
4593 if (target == GL_TRANSFORM_FEEDBACK_BUFFER && m_transformFeedbackBinding) {
4594 synthesizeGLError(GL_INVALID_OPERATION, functionName,
4595 "targeted transform feedback buffer is bound");
4596 return "Invalid operation: targeted transform feedback buffer is bound";
4597 }
4598
4599 WebGLBuffer* sourceBuffer = validateBufferDataTarget(functionName, target);
4600 if (!sourceBuffer) {
4601 return "Invalid operation: no buffer bound to target";
4602 }
4603 *outSourceBuffer = sourceBuffer;
4604
4605 if (!validateSubSourceAndGetData(
4606 destinationArrayBufferView, destinationOffset, length,
4607 outDestinationDataPtr, outDestinationByteLength)) {
4608 synthesizeGLError(GL_INVALID_VALUE, functionName, "overflow of dstData");
4609 return "Invalid value: overflow of dstData";
4610 }
4611
4612 return nullptr;
4613 }
4614
4615 const char* WebGL2RenderingContextBase::validateGetBufferSubDataBounds(
4616 const char* functionName,
4617 WebGLBuffer* sourceBuffer,
4618 GLintptr srcByteOffset,
4619 long long subByteLength) {
4620 CheckedNumeric<long long> srcEnd = srcByteOffset;
4621 srcEnd += subByteLength;
4622 if (!srcEnd.IsValid() || srcEnd.ValueOrDie() > sourceBuffer->getSize()) {
4623 synthesizeGLError(GL_INVALID_VALUE, functionName,
4624 "overflow of bound buffer");
4625 return "Invalid value: overflow of bound buffer";
4626 }
4627
4628 return nullptr;
4629 }
4630
4422 void WebGL2RenderingContextBase::removeBoundBuffer(WebGLBuffer* buffer) { 4631 void WebGL2RenderingContextBase::removeBoundBuffer(WebGLBuffer* buffer) {
4423 if (m_boundCopyReadBuffer == buffer) 4632 if (m_boundCopyReadBuffer == buffer)
4424 m_boundCopyReadBuffer = nullptr; 4633 m_boundCopyReadBuffer = nullptr;
4425 if (m_boundCopyWriteBuffer == buffer) 4634 if (m_boundCopyWriteBuffer == buffer)
4426 m_boundCopyWriteBuffer = nullptr; 4635 m_boundCopyWriteBuffer = nullptr;
4427 if (m_boundPixelPackBuffer == buffer) 4636 if (m_boundPixelPackBuffer == buffer)
4428 m_boundPixelPackBuffer = nullptr; 4637 m_boundPixelPackBuffer = nullptr;
4429 if (m_boundPixelUnpackBuffer == buffer) 4638 if (m_boundPixelUnpackBuffer == buffer)
4430 m_boundPixelUnpackBuffer = nullptr; 4639 m_boundPixelUnpackBuffer = nullptr;
4431 if (m_boundTransformFeedbackBuffer == buffer) 4640 if (m_boundTransformFeedbackBuffer == buffer)
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
4505 params.skipPixels = m_unpackSkipPixels; 4714 params.skipPixels = m_unpackSkipPixels;
4506 params.skipRows = m_unpackSkipRows; 4715 params.skipRows = m_unpackSkipRows;
4507 if (dimension == Tex3D) { 4716 if (dimension == Tex3D) {
4508 params.imageHeight = m_unpackImageHeight; 4717 params.imageHeight = m_unpackImageHeight;
4509 params.skipImages = m_unpackSkipImages; 4718 params.skipImages = m_unpackSkipImages;
4510 } 4719 }
4511 return params; 4720 return params;
4512 } 4721 }
4513 4722
4514 } // namespace blink 4723 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698