bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dstDUI, GLint xOffset, GLint yOffset, GLint zOffset, GLenum* const out_error) const { WebGLContext* webgl = tex->mContext; WebGLTexelFormat srcFormat; uint8_t srcBPP; if (!GetFormatForSurf(mSurf, &srcFormat, &srcBPP)) { webgl->ErrorImplementationBug("%s: GetFormatForSurf failed for" " WebGLTexelFormat::%u.", funcName, uint32_t(mSurf->GetFormat())); return false; } gfx::DataSourceSurface::ScopedMap map(mSurf, gfx::DataSourceSurface::MapType::READ); if (!map.IsMapped()) return false; const auto srcBytes = map.GetData(); const auto srcStride = map.GetStride(); // CPU conversion. (++numCopies) webgl->GenerateWarning("%s: Incurred CPU-side conversion, which is very slow.", funcName); const uint8_t* uploadBytes; UniqueBuffer tempBuffer; if (!ConvertIfNeeded(webgl, funcName, srcBytes, srcStride, srcBPP, srcFormat, dstDUI, &uploadBytes, &tempBuffer)) { return false; } ////// gl::GLContext* const gl = webgl->gl; MOZ_ALWAYS_TRUE( gl->MakeCurrent() ); const auto curEffectiveRowLength = FallbackOnZero(webgl->mPixelStore_UnpackRowLength, mWidth); const bool changeRowLength = (mRowLength != curEffectiveRowLength); if (changeRowLength) { MOZ_ASSERT(webgl->IsWebGL2()); gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength); } *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dstDUI, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, uploadBytes); if (changeRowLength) { gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, webgl->mPixelStore_UnpackRowLength); } return true; }
bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset, const webgl::PackingInfo& dstPI, GLenum* const out_error) const { const auto& webgl = tex->mContext; //// const auto rowLength = mSurf->GetSize().width; const auto rowCount = mSurf->GetSize().height; const auto& dstBPP = webgl::BytesPerPixel(dstPI); const auto dstFormat = FormatForPackingInfo(dstPI); //// WebGLTexelFormat srcFormat; uint8_t srcBPP; if (!GetFormatForSurf(mSurf, &srcFormat, &srcBPP)) { webgl->ErrorImplementationBug("%s: GetFormatForSurf failed for" " WebGLTexelFormat::%u.", funcName, uint32_t(mSurf->GetFormat())); return false; } gfx::DataSourceSurface::ScopedMap map(mSurf, gfx::DataSourceSurface::MapType::READ); if (!map.IsMapped()) { webgl->ErrorOutOfMemory("%s: Failed to map source surface for upload.", funcName); return false; } const auto& srcBegin = map.GetData(); const auto& srcStride = map.GetStride(); //// const auto srcRowLengthBytes = rowLength * srcBPP; const uint8_t maxGLAlignment = 8; uint8_t srcAlignment = 1; for (; srcAlignment <= maxGLAlignment; srcAlignment *= 2) { const auto strideGuess = RoundUpToMultipleOf(srcRowLengthBytes, srcAlignment); if (strideGuess == srcStride) break; } const uint32_t dstAlignment = (srcAlignment > maxGLAlignment) ? 1 : srcAlignment; const auto dstRowLengthBytes = rowLength * dstBPP; const auto dstStride = RoundUpToMultipleOf(dstRowLengthBytes, dstAlignment); //// const uint8_t* dstBegin = srcBegin; UniqueBuffer tempBuffer; if (!ConvertIfNeeded(webgl, funcName, rowLength, rowCount, srcFormat, srcBegin, srcStride, dstFormat, dstStride, &dstBegin, &tempBuffer)) { return false; } //// const auto& gl = webgl->gl; if (!gl->MakeCurrent()) { *out_error = LOCAL_GL_CONTEXT_LOST; return true; } gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, dstAlignment); if (webgl->IsWebGL2()) { gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength); } *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, dstBegin); gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, webgl->mPixelStore_UnpackAlignment); if (webgl->IsWebGL2()) { gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, webgl->mPixelStore_UnpackRowLength); } return true; }
/*static*/ bool TexUnpackSurface::ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackInfo* dui, gfx::DataSourceSurface* surf, bool isSurfAlphaPremult, UniqueBuffer* const out_convertedBuffer, uint8_t* const out_convertedAlignment, bool* const out_outOfMemory) { *out_outOfMemory = false; const size_t width = surf->GetSize().width; const size_t height = surf->GetSize().height; // Source args: // After we call this, on OSX, our GLContext will no longer be current. gfx::DataSourceSurface::ScopedMap srcMap(surf, gfx::DataSourceSurface::MapType::READ); if (!srcMap.IsMapped()) return false; const void* const srcBegin = srcMap.GetData(); const size_t srcStride = srcMap.GetStride(); WebGLTexelFormat srcFormat; if (!GetFormatForSurf(surf, &srcFormat)) return false; const bool srcPremultiplied = isSurfAlphaPremult; // Dest args: WebGLTexelFormat dstFormat; if (!GetFormatForPackingTuple(dui->unpackFormat, dui->unpackType, &dstFormat)) return false; const auto bytesPerPixel = webgl::BytesPerPixel({dui->unpackFormat, dui->unpackType}); const size_t dstRowBytes = bytesPerPixel * width; const size_t dstAlignment = 8; // Just use the max! const size_t dstStride = RoundUpToMultipleOf(dstRowBytes, dstAlignment); CheckedUint32 checkedDstSize = dstStride; checkedDstSize *= height; if (!checkedDstSize.isValid()) { *out_outOfMemory = true; return false; } const size_t dstSize = checkedDstSize.value(); UniqueBuffer dstBuffer = malloc(dstSize); if (!dstBuffer) { *out_outOfMemory = true; return false; } void* const dstBegin = dstBuffer.get(); gl::OriginPos srcOrigin, dstOrigin; OriginsForDOM(webgl, &srcOrigin, &dstOrigin); const bool dstPremultiplied = webgl->mPixelStore_PremultiplyAlpha; // And go!: if (!ConvertImage(width, height, srcBegin, srcStride, srcOrigin, srcFormat, srcPremultiplied, dstBegin, dstStride, dstOrigin, dstFormat, dstPremultiplied)) { MOZ_ASSERT(false, "ConvertImage failed unexpectedly."); NS_ERROR("ConvertImage failed unexpectedly."); *out_outOfMemory = true; return false; } *out_convertedBuffer = Move(dstBuffer); *out_convertedAlignment = dstAlignment; return true; }