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 b3eabd11b014fe35add63b9d0e4bf2b2c390d7cd..362bdccc3a3e66943b7ac68ad9949a284a4a7d9d 100644 |
| --- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp |
| +++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp |
| @@ -41,6 +41,109 @@ GLsync syncObjectOrZero(const WebGLSync* object) |
| return object ? object->object() : nullptr; |
| } |
| +class SubArrayBufferView { |
| +public: |
| + SubArrayBufferView(WTF::ArrayBufferView::ViewType viewType, void* viewBaseAddress, long long viewByteLength, GLuint subOffset, GLuint subLength) |
|
Ken Russell (switch to Gerrit)
2016/08/20 03:05:35
Is "long long" the best type to use for viewByteLe
Zhenyao Mo
2016/08/20 03:44:23
This is to match all the other byteLength types in
|
| + : m_viewType(viewType) |
| + , m_viewBaseAddress(viewBaseAddress) |
| + , m_viewByteLength(viewByteLength) |
| + , m_subOffset(subOffset) |
| + , m_subLength(subLength) |
|
Ken Russell (switch to Gerrit)
2016/08/20 03:05:35
Since initialize() returns void, what about moving
Zhenyao Mo
2016/08/20 03:44:23
That was my original design, but I remmebered we a
Ken Russell (switch to Gerrit)
2016/08/20 04:03:34
I think it'd be OK, and quite a bit simpler.
Zhenyao Mo
2016/08/23 00:22:42
Done.
|
| + , m_initialized(false) |
| + , m_subBaseAddress(nullptr) |
| + , m_subByteLength(0) |
| + , m_valid(false) |
| + { |
| + } |
| + |
| + bool isValid() |
| + { |
| + initialize(); |
|
Ken Russell (switch to Gerrit)
2016/08/20 03:05:35
Per above, suggest moving the call to initialize()
|
| + return m_valid; |
| + } |
| + |
| + void* baseAddress() const |
| + { |
| + DCHECK(m_initialized); |
| + return m_subBaseAddress; |
| + } |
| + |
| + long long byteLength() const |
| + { |
| + DCHECK(m_initialized); |
| + return m_subByteLength; |
| + } |
| + |
| +private: |
| + void initialize() |
| + { |
| + if (m_initialized) |
| + return; |
| + m_initialized = true; |
| + size_t typeSize = getViewTypeSize(m_viewType); |
| + DCHECK_GE(8u, typeSize); |
| + long long byteLength = 0; |
| + if (m_subLength) { |
| + // type size is at most 8, so no overflow. |
| + byteLength = m_subLength * typeSize; |
| + } |
| + long long byteOffset = 0; |
| + if (m_subOffset) { |
| + // type size is at most 8, so no overflow. |
| + byteOffset = m_subOffset * typeSize; |
| + } |
| + CheckedInt<long long> total = byteOffset; |
| + total += byteLength; |
| + if (!total.isValid() || total.value() > m_viewByteLength) { |
| + return; |
| + } |
|
Ken Russell (switch to Gerrit)
2016/08/20 03:05:35
Should there be a separate check like:
if (!byt
Zhenyao Mo
2016/08/20 03:44:23
Looking at bufferSubData, where the offset is beyo
Ken Russell (switch to Gerrit)
2016/08/20 04:05:55
As long as the tests verify this, sounds good. It'
|
| + if (!byteLength) { |
| + byteLength = m_viewByteLength - byteOffset; |
| + } |
| + uint8_t* data = static_cast<uint8_t*>(m_viewBaseAddress); |
| + data += byteOffset; |
|
Ken Russell (switch to Gerrit)
2016/08/20 03:05:35
Any possibility of overflow on the address? Should
Zhenyao Mo
2016/08/20 03:44:23
We already checked byteOffset is within the ArrayB
|
| + m_subBaseAddress = data; |
| + m_subByteLength = byteLength; |
| + m_valid = true; |
| + } |
| + |
| + static size_t getViewTypeSize(WTF::ArrayBufferView::ViewType viewType) |
| + { |
| + switch (viewType) { |
| + case WTF::ArrayBufferView::TypeInt8: |
| + case WTF::ArrayBufferView::TypeUint8: |
| + case WTF::ArrayBufferView::TypeUint8Clamped: |
| + return 1; |
| + case WTF::ArrayBufferView::TypeInt16: |
| + case WTF::ArrayBufferView::TypeUint16: |
| + return 2; |
| + case WTF::ArrayBufferView::TypeInt32: |
| + case WTF::ArrayBufferView::TypeUint32: |
| + case WTF::ArrayBufferView::TypeFloat32: |
| + return 4; |
| + case WTF::ArrayBufferView::TypeFloat64: |
| + return 8; |
| + case WTF::ArrayBufferView::TypeDataView: |
| + return 1; |
| + default: |
| + NOTREACHED(); |
| + return 0; |
| + } |
| + } |
| + |
| + WTF::ArrayBufferView::ViewType m_viewType; |
| + void* m_viewBaseAddress; |
| + long long m_viewByteLength; |
| + GLuint m_subOffset; |
| + GLuint m_subLength; |
| + |
| + bool m_initialized; |
|
Ken Russell (switch to Gerrit)
2016/08/20 03:05:35
I think it's possible and desirable to eliminate a
Zhenyao Mo
2016/08/20 03:44:23
Now I think again, we can actually just do this in
|
| + |
| + void* m_subBaseAddress; |
| + long long m_subByteLength; |
| + bool m_valid; |
| +}; |
| + |
| } // namespace |
| // These enums are from manual pages for glTexStorage2D/glTexStorage3D. |
| @@ -183,6 +286,57 @@ void WebGL2RenderingContextBase::initializeNewContext() |
| WebGLRenderingContextBase::initializeNewContext(); |
| } |
| +void WebGL2RenderingContextBase::bufferData(GLenum target, DOMArrayBufferView* srcData, GLenum usage, GLuint srcOffset, GLuint length) |
| +{ |
| + if (isContextLost()) |
| + return; |
| + DCHECK(srcData); |
|
Ken Russell (switch to Gerrit)
2016/08/20 03:05:35
Maybe worth adding a comment that this is guarante
Zhenyao Mo
2016/08/20 03:44:23
Will do.
|
| + SubArrayBufferView subView(srcData->type(), srcData->baseAddress(), srcData->byteLength(), srcOffset, length); |
|
Ken Russell (switch to Gerrit)
2016/08/20 03:05:35
Perhaps the SubArrayBufferView constructor should
Zhenyao Mo
2016/08/20 03:44:23
The reason I didn't pass DOMArrayBufferView is tha
|
| + if (!subView.isValid()) { |
| + synthesizeGLError(GL_INVALID_VALUE, "bufferData", "srcOffset + length too large"); |
| + return; |
| + } |
| + bufferDataImpl(target, subView.byteLength(), subView.baseAddress(), usage); |
| +} |
| + |
| +void WebGL2RenderingContextBase::bufferData(GLenum target, long long size, GLenum usage) |
| +{ |
| + WebGLRenderingContextBase::bufferData(target, size, usage); |
| +} |
| + |
| +void WebGL2RenderingContextBase::bufferData(GLenum target, DOMArrayBuffer* data, GLenum usage) |
| +{ |
| + WebGLRenderingContextBase::bufferData(target, data, usage); |
| +} |
| + |
| +void WebGL2RenderingContextBase::bufferData(GLenum target, DOMArrayBufferView* data, GLenum usage) |
| +{ |
| + WebGLRenderingContextBase::bufferData(target, data, usage); |
| +} |
| + |
| +void WebGL2RenderingContextBase::bufferSubData(GLenum target, GLintptr dstByteOffset, DOMArrayBufferView* srcData, GLuint srcOffset, GLuint length) |
| +{ |
| + if (isContextLost()) |
| + return; |
| + DCHECK(srcData); |
| + SubArrayBufferView subView(srcData->type(), srcData->baseAddress(), srcData->byteLength(), srcOffset, length); |
| + if (!subView.isValid()) { |
| + synthesizeGLError(GL_INVALID_VALUE, "bufferSubData", "srcOffset + length too large"); |
| + return; |
| + } |
| + bufferSubDataImpl(target, dstByteOffset, subView.byteLength(), subView.baseAddress()); |
| +} |
| + |
| +void WebGL2RenderingContextBase::bufferSubData(GLenum target, long long offset, DOMArrayBuffer* data) |
| +{ |
| + WebGLRenderingContextBase::bufferSubData(target, offset, data); |
| +} |
| + |
| +void WebGL2RenderingContextBase::bufferSubData(GLenum target, long long offset, const FlexibleArrayBufferView& data) |
| +{ |
| + WebGLRenderingContextBase::bufferSubData(target, offset, data); |
| +} |
| + |
| void WebGL2RenderingContextBase::copyBufferSubData(GLenum readTarget, GLenum writeTarget, long long readOffset, long long writeOffset, long long size) |
| { |
| if (isContextLost()) |
| @@ -219,34 +373,34 @@ void WebGL2RenderingContextBase::copyBufferSubData(GLenum readTarget, GLenum wri |
| contextGL()->CopyBufferSubData(readTarget, writeTarget, static_cast<GLintptr>(readOffset), static_cast<GLintptr>(writeOffset), static_cast<GLsizeiptr>(size)); |
| } |
| -void WebGL2RenderingContextBase::getBufferSubData(GLenum target, long long offset, DOMArrayBuffer* returnedData) |
| +void WebGL2RenderingContextBase::getBufferSubData(GLenum target, long long srcByteOffset, DOMArrayBufferView* dstData, GLuint dstOffset, GLuint length) |
| { |
| + const char* funcName = "getBufferSubData"; |
| if (isContextLost()) |
| return; |
| - |
| - if (!returnedData) { |
| - synthesizeGLError(GL_INVALID_VALUE, "getBufferSubData", "ArrayBuffer cannot be null"); |
| + if (!validateValueFitNonNegInt32(funcName, "srcByteOffset", srcByteOffset)) { |
| return; |
| } |
| - |
| - if (!validateValueFitNonNegInt32("getBufferSubData", "offset", offset)) { |
| + WebGLBuffer* buffer = validateBufferDataTarget(funcName, target); |
| + if (!buffer) |
| return; |
| + DCHECK(dstData); |
| + SubArrayBufferView subView(dstData->type(), dstData->baseAddress(), dstData->byteLength(), dstOffset, length); |
| + if (!subView.isValid()) { |
| + synthesizeGLError(GL_INVALID_VALUE, funcName, "dstOffset + length too large"); |
|
Ken Russell (switch to Gerrit)
2016/08/20 03:05:35
Return too, correct?
Zhenyao Mo
2016/08/20 03:44:23
Ah thanks for catching this.
|
| } |
| - WebGLBuffer* buffer = validateBufferDataTarget("getBufferSubData", target); |
| - if (!buffer) |
| - return; |
| - if (offset + returnedData->byteLength() > buffer->getSize()) { |
| - synthesizeGLError(GL_INVALID_VALUE, "getBufferSubData", "buffer overflow"); |
| + if (srcByteOffset + subView.byteLength() > buffer->getSize()) { |
| + synthesizeGLError(GL_INVALID_VALUE, funcName, "buffer overflow"); |
| return; |
| } |
| - void* mappedData = contextGL()->MapBufferRange(target, static_cast<GLintptr>(offset), returnedData->byteLength(), GL_MAP_READ_BIT); |
| + void* mappedData = contextGL()->MapBufferRange(target, static_cast<GLintptr>(srcByteOffset), subView.byteLength(), GL_MAP_READ_BIT); |
| if (!mappedData) |
| return; |
| - memcpy(returnedData->data(), mappedData, returnedData->byteLength()); |
| + memcpy(subView.baseAddress(), mappedData, subView.byteLength()); |
| contextGL()->UnmapBuffer(target); |
| } |