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::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage) { if (IsContextLost()) return; if (!ValidateBufferTarget(target, "bufferData")) return; WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target); if (size < 0) return ErrorInvalidValue("bufferData: negative size"); if (!ValidateBufferUsageEnum(usage, "bufferData: usage")) return; // careful: WebGLsizeiptr is always 64-bit, but GLsizeiptr is like intptr_t. if (!CheckedInt<GLsizeiptr>(size).isValid()) return ErrorOutOfMemory("bufferData: bad size"); WebGLBuffer* boundBuffer = bufferSlot.get(); if (!boundBuffer) return ErrorInvalidOperation("bufferData: no buffer bound!"); UniquePtr<uint8_t> zeroBuffer((uint8_t*)calloc(size, 1)); if (!zeroBuffer) return ErrorOutOfMemory("bufferData: out of memory"); MakeContextCurrent(); InvalidateBufferFetching(); GLenum error = CheckedBufferData(target, size, zeroBuffer.get(), usage); if (error) { GenerateWarning("bufferData generated error %s", ErrorName(error)); return; } boundBuffer->SetByteLength(size); if (!boundBuffer->ElementArrayCacheBufferData(nullptr, size)) { return ErrorOutOfMemory("bufferData: out of memory"); } }
void WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage) { const FuncScope funcScope(*this, "bufferData"); if (IsContextLost()) return; if (!ValidateNonNegative("size", size)) return; //// const auto checkedSize = CheckedInt<size_t>(size); if (!checkedSize.isValid()) return ErrorOutOfMemory("size too large for platform."); const UniqueBuffer zeroBuffer(calloc(checkedSize.value(), 1u)); if (!zeroBuffer) return ErrorOutOfMemory("Failed to allocate zeros."); BufferDataImpl(target, uint64_t{checkedSize.value()}, (const uint8_t*)zeroBuffer.get(), usage); }
void WebGLContext::BufferDataT(GLenum target, const BufferT& data, GLenum usage) { if (IsContextLost()) return; if (!ValidateBufferTarget(target, "bufferData")) return; const WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target); data.ComputeLengthAndData(); // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr // is like intptr_t. if (!CheckedInt<GLsizeiptr>(data.Length()).isValid()) return ErrorOutOfMemory("bufferData: bad size"); if (!ValidateBufferUsageEnum(usage, "bufferData: usage")) return; WebGLBuffer* boundBuffer = bufferSlot.get(); if (!boundBuffer) return ErrorInvalidOperation("bufferData: no buffer bound!"); MakeContextCurrent(); InvalidateBufferFetching(); GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage); if (error) { GenerateWarning("bufferData generated error %s", ErrorName(error)); return; } boundBuffer->SetByteLength(data.Length()); if (!boundBuffer->ElementArrayCacheBufferData(data.Data(), data.Length())) return ErrorOutOfMemory("bufferData: out of memory"); }
void WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage) { const char funcName[] = "bufferData"; if (IsContextLost()) return; if (!ValidateNonNegative(funcName, "size", size)) return; //// 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 WebGL2Context::GetActiveUniforms(JSContext* cx, const WebGLProgram& program, const dom::Sequence<GLuint>& uniformIndices, GLenum pname, JS::MutableHandleValue retval) { const char funcName[] = "getActiveUniforms"; retval.setNull(); if (IsContextLost()) return; if (!ValidateUniformEnum(this, pname, funcName)) return; if (!ValidateObject("getActiveUniforms: program", program)) return; const auto& numActiveUniforms = program.LinkInfo()->uniforms.size(); for (const auto& curIndex : uniformIndices) { if (curIndex >= numActiveUniforms) { ErrorInvalidValue("%s: Too-large active uniform index queried.", funcName); return; } } const auto& count = uniformIndices.Length(); JS::Rooted<JSObject*> array(cx, JS_NewArrayObject(cx, count)); UniquePtr<GLint[]> samples(new GLint[count]); if (!array || !samples) { ErrorOutOfMemory("%s: Failed to allocate buffers.", funcName); return; } retval.setObject(*array); MakeContextCurrent(); gl->fGetActiveUniformsiv(program.mGLName, count, uniformIndices.Elements(), pname, samples.get()); switch (pname) { case LOCAL_GL_UNIFORM_TYPE: case LOCAL_GL_UNIFORM_SIZE: case LOCAL_GL_UNIFORM_BLOCK_INDEX: case LOCAL_GL_UNIFORM_OFFSET: case LOCAL_GL_UNIFORM_ARRAY_STRIDE: case LOCAL_GL_UNIFORM_MATRIX_STRIDE: for (size_t i = 0; i < count; ++i) { JS::RootedValue value(cx); value = JS::Int32Value(samples[i]); if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE)) return; } break; case LOCAL_GL_UNIFORM_IS_ROW_MAJOR: for (size_t i = 0; i < count; ++i) { JS::RootedValue value(cx); value = JS::BooleanValue(samples[i]); if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE)) return; } break; default: MOZ_CRASH("Invalid pname"); } }
bool WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount) { WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need(); if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)) return true; if (!mAlreadyWarnedAboutFakeVertexAttrib0) { GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser " "to do expensive emulation work when running on desktop OpenGL " "platforms, for example on Mac. It is preferable to always draw " "with vertex attrib 0 array enabled, by using bindAttribLocation " "to bind some always-used attribute to location 0."); mAlreadyWarnedAboutFakeVertexAttrib0 = true; } CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(GLfloat); if (!checked_dataSize.isValid()) { ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation " "with %d vertices. Try reducing the number of vertices.", vertexCount); return false; } GLuint dataSize = checked_dataSize.value(); if (!mFakeVertexAttrib0BufferObject) { gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject); } // if the VBO status is already exactly what we need, or if the only difference is that it's initialized and // we don't need it to be, then consider it OK bool vertexAttrib0BufferStatusOK = mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need || (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray && whatDoesAttrib0Need == WebGLVertexAttrib0Status::EmulatedUninitializedArray); if (!vertexAttrib0BufferStatusOK || mFakeVertexAttrib0BufferObjectSize < dataSize || mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] || mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] || mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] || mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3]) { mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need; mFakeVertexAttrib0BufferObjectSize = dataSize; mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0]; mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1]; mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2]; mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3]; gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject); GetAndFlushUnderlyingGLErrors(); if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) { auto array = MakeUniqueFallible<GLfloat[]>(4 * vertexCount); if (!array) { ErrorOutOfMemory("Fake attrib0 array."); return false; } for(size_t i = 0; i < vertexCount; ++i) { array[4 * i + 0] = mVertexAttrib0Vector[0]; array[4 * i + 1] = mVertexAttrib0Vector[1]; array[4 * i + 2] = mVertexAttrib0Vector[2]; array[4 * i + 3] = mVertexAttrib0Vector[3]; } gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array.get(), LOCAL_GL_DYNAMIC_DRAW); } else { gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW); } GLenum error = GetAndFlushUnderlyingGLErrors(); gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0); // note that we do this error checking and early return AFTER having restored the buffer binding above if (error) { ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation " "with %d vertices. Try reducing the number of vertices.", vertexCount); return false; } } gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject); gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0); return true; }