123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "WebGLContext.h"
- #include "GLContext.h"
- #include "WebGLBuffer.h"
- #include "WebGLTransformFeedback.h"
- #include "WebGLVertexArray.h"
- #include "mozilla/CheckedInt.h"
- namespace mozilla {
- WebGLRefPtr<WebGLBuffer>*
- WebGLContext::ValidateBufferSlot(const char* funcName, GLenum target)
- {
- WebGLRefPtr<WebGLBuffer>* slot = nullptr;
- switch (target) {
- case LOCAL_GL_ARRAY_BUFFER:
- slot = &mBoundArrayBuffer;
- break;
- case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
- slot = &(mBoundVertexArray->mElementArrayBuffer);
- break;
- }
- if (IsWebGL2()) {
- switch (target) {
- case LOCAL_GL_COPY_READ_BUFFER:
- slot = &mBoundCopyReadBuffer;
- break;
- case LOCAL_GL_COPY_WRITE_BUFFER:
- slot = &mBoundCopyWriteBuffer;
- break;
- case LOCAL_GL_PIXEL_PACK_BUFFER:
- slot = &mBoundPixelPackBuffer;
- break;
- case LOCAL_GL_PIXEL_UNPACK_BUFFER:
- slot = &mBoundPixelUnpackBuffer;
- break;
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- slot = &(mBoundTransformFeedback->mGenericBufferBinding);
- break;
- case LOCAL_GL_UNIFORM_BUFFER:
- slot = &mBoundUniformBuffer;
- break;
- }
- }
- if (!slot) {
- ErrorInvalidEnum("%s: Bad `target`: 0x%04x", funcName, target);
- return nullptr;
- }
- return slot;
- }
- WebGLBuffer*
- WebGLContext::ValidateBufferSelection(const char* funcName, GLenum target)
- {
- const auto& slot = ValidateBufferSlot(funcName, target);
- if (!slot)
- return nullptr;
- const auto& buffer = *slot;
- if (!buffer) {
- ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
- return nullptr;
- }
- if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) {
- if (mBoundTransformFeedback->IsActiveAndNotPaused()) {
- ErrorInvalidOperation("%s: Cannot select TRANSFORM_FEEDBACK_BUFFER when"
- " transform feedback is active and unpaused.",
- funcName);
- return nullptr;
- }
- if (buffer->IsBoundForNonTF()) {
- ErrorInvalidOperation("%s: Specified WebGLBuffer is currently bound for"
- " non-transform-feedback.",
- funcName);
- return nullptr;
- }
- } else {
- if (buffer->IsBoundForTF()) {
- ErrorInvalidOperation("%s: Specified WebGLBuffer is currently bound for"
- " transform feedback.",
- funcName);
- return nullptr;
- }
- }
- return buffer.get();
- }
- IndexedBufferBinding*
- WebGLContext::ValidateIndexedBufferSlot(const char* funcName, GLenum target, GLuint index)
- {
- decltype(mIndexedUniformBufferBindings)* bindings;
- const char* maxIndexEnum;
- switch (target) {
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- bindings = &(mBoundTransformFeedback->mIndexedBindings);
- maxIndexEnum = "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS";
- break;
- case LOCAL_GL_UNIFORM_BUFFER:
- bindings = &mIndexedUniformBufferBindings;
- maxIndexEnum = "MAX_UNIFORM_BUFFER_BINDINGS";
- break;
- default:
- ErrorInvalidEnum("%s: Bad `target`: 0x%04x", funcName, target);
- return nullptr;
- }
- if (index >= bindings->size()) {
- ErrorInvalidValue("%s: `index` >= %s.", funcName, maxIndexEnum);
- return nullptr;
- }
- return &(*bindings)[index];
- }
- ////////////////////////////////////////
- void
- WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer)
- {
- const char funcName[] = "bindBuffer";
- if (IsContextLost())
- return;
- if (buffer && !ValidateObject(funcName, *buffer))
- return;
- const auto& slot = ValidateBufferSlot(funcName, target);
- if (!slot)
- return;
- if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
- return;
- gl->MakeCurrent();
- gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
- WebGLBuffer::SetSlot(target, buffer, slot);
- if (buffer) {
- buffer->SetContentAfterBind(target);
- }
- switch (target) {
- case LOCAL_GL_PIXEL_PACK_BUFFER:
- case LOCAL_GL_PIXEL_UNPACK_BUFFER:
- gl->fBindBuffer(target, 0);
- break;
- }
- }
- ////////////////////////////////////////
- bool
- WebGLContext::ValidateIndexedBufferBinding(const char* funcName, GLenum target,
- GLuint index,
- WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
- IndexedBufferBinding** const out_indexedBinding)
- {
- *out_genericBinding = ValidateBufferSlot(funcName, target);
- if (!*out_genericBinding)
- return false;
- *out_indexedBinding = ValidateIndexedBufferSlot(funcName, target, index);
- if (!*out_indexedBinding)
- return false;
- if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
- mBoundTransformFeedback->mIsActive)
- {
- ErrorInvalidOperation("%s: Cannot update indexed buffer bindings on active"
- " transform feedback objects.",
- funcName);
- return false;
- }
- return true;
- }
- void
- WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
- {
- const char funcName[] = "bindBufferBase";
- if (IsContextLost())
- return;
- if (buffer && !ValidateObject(funcName, *buffer))
- return;
- WebGLRefPtr<WebGLBuffer>* genericBinding;
- IndexedBufferBinding* indexedBinding;
- if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
- &indexedBinding))
- {
- return;
- }
- if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
- return;
- ////
- gl->MakeCurrent();
- gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
- ////
- WebGLBuffer::SetSlot(target, buffer, genericBinding);
- WebGLBuffer::SetSlot(target, buffer, &indexedBinding->mBufferBinding);
- indexedBinding->mRangeStart = 0;
- indexedBinding->mRangeSize = 0;
- if (buffer) {
- buffer->SetContentAfterBind(target);
- }
- }
- void
- WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
- WebGLintptr offset, WebGLsizeiptr size)
- {
- const char funcName[] = "bindBufferRange";
- if (IsContextLost())
- return;
- if (buffer && !ValidateObject(funcName, *buffer))
- return;
- if (!ValidateNonNegative(funcName, "offset", offset) ||
- !ValidateNonNegative(funcName, "size", size))
- {
- return;
- }
- WebGLRefPtr<WebGLBuffer>* genericBinding;
- IndexedBufferBinding* indexedBinding;
- if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
- &indexedBinding))
- {
- return;
- }
- if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
- return;
- if (buffer && !size) {
- ErrorInvalidValue("%s: size must be non-zero for non-null buffer.", funcName);
- return;
- }
- ////
- gl->MakeCurrent();
- switch (target) {
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- if (offset % 4 != 0 || size % 4 != 0) {
- ErrorInvalidValue("%s: For %s, `offset` and `size` must be multiples of 4.",
- funcName, "TRANSFORM_FEEDBACK_BUFFER");
- return;
- }
- break;
- case LOCAL_GL_UNIFORM_BUFFER:
- {
- GLuint offsetAlignment = 0;
- gl->GetUIntegerv(LOCAL_GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offsetAlignment);
- if (offset % offsetAlignment != 0) {
- ErrorInvalidValue("%s: For %s, `offset` must be a multiple of %s.",
- funcName, "UNIFORM_BUFFER",
- "UNIFORM_BUFFER_OFFSET_ALIGNMENT");
- return;
- }
- }
- break;
- }
- ////
- gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset, size);
- ////
- WebGLBuffer::SetSlot(target, buffer, genericBinding);
- WebGLBuffer::SetSlot(target, buffer, &indexedBinding->mBufferBinding);
- indexedBinding->mRangeStart = offset;
- indexedBinding->mRangeSize = size;
- if (buffer) {
- buffer->SetContentAfterBind(target);
- }
- }
- ////////////////////////////////////////
- void
- WebGLContext::BufferDataImpl(GLenum target, size_t dataLen, const uint8_t* data,
- GLenum usage)
- {
- const char funcName[] = "bufferData";
- const auto& buffer = ValidateBufferSelection(funcName, target);
- if (!buffer)
- return;
- buffer->BufferData(target, dataLen, data, usage);
- }
- ////
- void
- WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
- {
- const char funcName[] = "bufferData";
- if (IsContextLost())
- return;
- if (!ValidateNonNegative(funcName, "size", size))
- return;
- ////
- const auto checkedSize = CheckedInt<size_t>(size);
- if (!checkedSize.isValid())
- return ErrorOutOfMemory("%s: Size too large for platform.", funcName);
-
- const UniqueBuffer zeroBuffer(calloc(size, 1));
- if (!zeroBuffer)
- return ErrorOutOfMemory("%s: Failed to allocate zeros.", funcName);
- BufferDataImpl(target, size_t(size), (const uint8_t*)zeroBuffer.get(), usage);
- }
- void
- WebGLContext::BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeSrc,
- GLenum usage)
- {
- if (IsContextLost())
- return;
- if (!ValidateNonNull("bufferData", maybeSrc))
- return;
- const auto& src = maybeSrc.Value();
- src.ComputeLengthAndData();
- BufferDataImpl(target, src.LengthAllowShared(), src.DataAllowShared(), usage);
- }
- void
- WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& src, GLenum usage,
- GLuint srcElemOffset, GLuint srcElemCountOverride)
- {
- const char funcName[] = "bufferData";
- if (IsContextLost())
- return;
- uint8_t* bytes;
- size_t byteLen;
- if (!ValidateArrayBufferView(funcName, src, srcElemOffset, srcElemCountOverride,
- &bytes, &byteLen))
- {
- return;
- }
- BufferDataImpl(target, byteLen, bytes, usage);
- }
- ////////////////////////////////////////
- void
- WebGLContext::BufferSubDataImpl(GLenum target, WebGLsizeiptr dstByteOffset,
- size_t dataLen, const uint8_t* data)
- {
- const char funcName[] = "bufferSubData";
- if (!ValidateNonNegative(funcName, "byteOffset", dstByteOffset))
- return;
- const auto& buffer = ValidateBufferSelection(funcName, target);
- if (!buffer)
- return;
- if (!buffer->ValidateRange(funcName, dstByteOffset, dataLen))
- return;
- if (!CheckedInt<GLintptr>(dataLen).isValid()) {
- ErrorOutOfMemory("%s: Size too large.", funcName);
- return;
- }
- const GLintptr glDataLen(dataLen);
- ////
- MakeContextCurrent();
- const ScopedLazyBind lazyBind(gl, target, buffer);
- // Warning: Possibly shared memory. See bug 1225033.
- gl->fBufferSubData(target, dstByteOffset, glDataLen, data);
- // Warning: Possibly shared memory. See bug 1225033.
- buffer->ElementArrayCacheBufferSubData(dstByteOffset, data, size_t(glDataLen));
- }
- void
- WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
- const dom::ArrayBuffer& src)
- {
- if (IsContextLost())
- return;
- src.ComputeLengthAndData();
- BufferSubDataImpl(target, dstByteOffset, src.LengthAllowShared(),
- src.DataAllowShared());
- }
- void
- WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
- const dom::ArrayBufferView& src, GLuint srcElemOffset,
- GLuint srcElemCountOverride)
- {
- const char funcName[] = "bufferSubData";
- if (IsContextLost())
- return;
- uint8_t* bytes;
- size_t byteLen;
- if (!ValidateArrayBufferView(funcName, src, srcElemOffset, srcElemCountOverride,
- &bytes, &byteLen))
- {
- return;
- }
- BufferSubDataImpl(target, dstByteOffset, byteLen, bytes);
- }
- ////////////////////////////////////////
- already_AddRefed<WebGLBuffer>
- WebGLContext::CreateBuffer()
- {
- if (IsContextLost())
- return nullptr;
- GLuint buf = 0;
- MakeContextCurrent();
- gl->fGenBuffers(1, &buf);
- RefPtr<WebGLBuffer> globj = new WebGLBuffer(this, buf);
- return globj.forget();
- }
- void
- WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
- {
- if (!ValidateDeleteObject("deleteBuffer", buffer))
- return;
- ////
- const auto fnClearIfBuffer = [&](GLenum target, WebGLRefPtr<WebGLBuffer>& bindPoint) {
- if (bindPoint == buffer) {
- WebGLBuffer::SetSlot(target, nullptr, &bindPoint);
- }
- };
- fnClearIfBuffer(0, mBoundArrayBuffer);
- fnClearIfBuffer(0, mBoundVertexArray->mElementArrayBuffer);
- for (auto& cur : mBoundVertexArray->mAttribs) {
- fnClearIfBuffer(0, cur.mBuf);
- }
- // WebGL binding points
- if (IsWebGL2()) {
- fnClearIfBuffer(0, mBoundCopyReadBuffer);
- fnClearIfBuffer(0, mBoundCopyWriteBuffer);
- fnClearIfBuffer(0, mBoundPixelPackBuffer);
- fnClearIfBuffer(0, mBoundPixelUnpackBuffer);
- fnClearIfBuffer(0, mBoundUniformBuffer);
- fnClearIfBuffer(LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER,
- mBoundTransformFeedback->mGenericBufferBinding);
- if (!mBoundTransformFeedback->mIsActive) {
- for (auto& binding : mBoundTransformFeedback->mIndexedBindings) {
- fnClearIfBuffer(LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER,
- binding.mBufferBinding);
- }
- }
- for (auto& binding : mIndexedUniformBufferBindings) {
- fnClearIfBuffer(0, binding.mBufferBinding);
- }
- }
- ////
- buffer->RequestDelete();
- }
- bool
- WebGLContext::IsBuffer(WebGLBuffer* buffer)
- {
- if (!ValidateIsObject("isBuffer", buffer))
- return false;
- MakeContextCurrent();
- return gl->fIsBuffer(buffer->mGLName);
- }
- } // namespace mozilla
|