char* KVStore::getInternal(const std::string& key, char**) { Transaction transaction(*this); ScopedReset scopedReset(mGetValueStmt); ::sqlite3_bind_text(mGetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT); int ret = ::sqlite3_step(mGetValueStmt->get()); if (ret == SQLITE_DONE) { throw ConfigException("No value corresponding to the key: " + key + "@" + mPath); } if (ret != SQLITE_ROW) { throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); } const char* source = reinterpret_cast<const char*>(sqlite3_column_text(mGetValueStmt->get(), FIRST_COLUMN)); size_t length = std::strlen(source); char* value = new char[length + 1]; std::strncpy(value, source, length); value[length] = '\0'; transaction.commit(); return value; }
void 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, GLenum* const out_glError) { *out_glError = 0; WebGLContext* webgl = tex->mContext; // MakeCurrent is a big mess in here, because mapping (and presumably unmapping) on // OSX can lose our MakeCurrent. Therefore it's easiest to MakeCurrent just before we // call into GL, instead of trying to keep MakeCurrent-ed. RefPtr<gfx::DataSourceSurface> dataSurf = mSurf->GetDataSurface(); if (!dataSurf) { // Since GetDataSurface didn't return error code, assume system // is out of memory *out_glError = LOCAL_GL_OUT_OF_MEMORY; return; } GLenum error; if (UploadDataSurface(isSubImage, webgl, target, level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, dataSurf, mIsAlphaPremult, &error)) { return; } if (error == LOCAL_GL_OUT_OF_MEMORY) { *out_glError = LOCAL_GL_OUT_OF_MEMORY; return; } // CPU conversion. (++numCopies) UniqueBuffer convertedBuffer; uint8_t convertedAlignment; bool outOfMemory; if (!ConvertSurface(webgl, dui, dataSurf, mIsAlphaPremult, &convertedBuffer, &convertedAlignment, &outOfMemory)) { if (outOfMemory) { *out_glError = LOCAL_GL_OUT_OF_MEMORY; } else { NS_ERROR("Failed to convert surface."); *out_glError = LOCAL_GL_OUT_OF_MEMORY; } return; } MOZ_ALWAYS_TRUE( webgl->gl->MakeCurrent() ); ScopedUnpackReset scopedReset(webgl); webgl->gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, convertedAlignment); error = DoTexOrSubImage(isSubImage, webgl->gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, convertedBuffer.get()); *out_glError = error; }
void KVStore::remove(const std::string& key) { Transaction transaction(*this); ScopedReset scopedReset(mRemoveValuesStmt); ::sqlite3_bind_text(mRemoveValuesStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC); if (::sqlite3_step(mRemoveValuesStmt->get()) != SQLITE_DONE) { throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); } transaction.commit(); }
bool KVStore::isEmpty() { Transaction transaction(*this); ScopedReset scopedReset(mGetIsEmptyStmt); int ret = ::sqlite3_step(mGetIsEmptyStmt->get()); if (ret != SQLITE_DONE && ret != SQLITE_ROW) { throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); } transaction.commit(); return ret == SQLITE_DONE; }
bool KVStore::exists(const std::string& key) { Transaction transaction(*this); ScopedReset scopedReset(mGetKeyExistsStmt); ::sqlite3_bind_text(mGetKeyExistsStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT); int ret = ::sqlite3_step(mGetKeyExistsStmt->get()); if (ret != SQLITE_DONE && ret != SQLITE_ROW) { throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); } transaction.commit(); return ret == SQLITE_ROW; }
std::vector<std::string> KVStore::getKeys() { Transaction transaction(*this); ScopedReset scopedReset(mGetKeysStmt); std::vector<std::string> result; for (;;) { int ret = ::sqlite3_step(mGetKeysStmt->get()); if (ret == SQLITE_DONE) { break; } if (ret != SQLITE_ROW) { throw ConfigException("Error during stepping: " + mConn.getErrorMessage()); } const char* key = reinterpret_cast<const char*>(sqlite3_column_text(mGetKeysStmt->get(), FIRST_COLUMN)); result.push_back(key); } transaction.commit(); return result; }
static bool ZeroTextureData(WebGLContext* webgl, const char* funcName, GLuint tex, TexImageTarget target, uint32_t level, const webgl::FormatUsageInfo* usage, uint32_t width, uint32_t height, uint32_t depth) { // This has two usecases: // 1. Lazy zeroing of uninitialized textures: // a. Before draw, when FakeBlack isn't viable. (TexStorage + Draw*) // b. Before partial upload. (TexStorage + TexSubImage) // 2. Zero subrects from out-of-bounds blits. (CopyTex(Sub)Image) // We have no sympathy for any of these cases. // "Doctor, it hurts when I do this!" "Well don't do that!" webgl->GenerateWarning("%s: This operation requires zeroing texture data. This is" " slow.", funcName); gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); GLenum scopeBindTarget; switch (target.get()) { case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: scopeBindTarget = LOCAL_GL_TEXTURE_CUBE_MAP; break; default: scopeBindTarget = target.get(); break; } const gl::ScopedBindTexture scopeBindTexture(gl, tex, scopeBindTarget); auto compression = usage->format->compression; if (compression) { auto sizedFormat = usage->format->sizedFormat; MOZ_RELEASE_ASSERT(sizedFormat, "GFX: texture sized format not set"); const auto fnSizeInBlocks = [](CheckedUint32 pixels, uint8_t pixelsPerBlock) { return RoundUpToMultipleOf(pixels, pixelsPerBlock) / pixelsPerBlock; }; const auto widthBlocks = fnSizeInBlocks(width, compression->blockWidth); const auto heightBlocks = fnSizeInBlocks(height, compression->blockHeight); CheckedUint32 checkedByteCount = compression->bytesPerBlock; checkedByteCount *= widthBlocks; checkedByteCount *= heightBlocks; checkedByteCount *= depth; if (!checkedByteCount.isValid()) return false; const size_t byteCount = checkedByteCount.value(); UniqueBuffer zeros = calloc(1, byteCount); if (!zeros) return false; ScopedUnpackReset scopedReset(webgl); gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it // well. const auto error = DoCompressedTexSubImage(gl, target.get(), level, 0, 0, 0, width, height, depth, sizedFormat, byteCount, zeros.get()); return !error; } const auto driverUnpackInfo = usage->idealUnpack; MOZ_RELEASE_ASSERT(driverUnpackInfo, "GFX: ideal unpack info not set."); if (webgl->IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) && gl->IsANGLE() && usage->format->d) { // ANGLE_depth_texture does not allow uploads, so we have to clear. // (Restriction because of D3D9) MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D); MOZ_ASSERT(level == 0); ZeroANGLEDepthTexture(webgl, tex, usage, width, height); return true; } const webgl::PackingInfo packing = driverUnpackInfo->ToPacking(); const auto bytesPerPixel = webgl::BytesPerPixel(packing); CheckedUint32 checkedByteCount = bytesPerPixel; checkedByteCount *= width; checkedByteCount *= height; checkedByteCount *= depth; if (!checkedByteCount.isValid()) return false; const size_t byteCount = checkedByteCount.value(); UniqueBuffer zeros = calloc(1, byteCount); if (!zeros) return false; ScopedUnpackReset scopedReset(webgl); gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well. const auto error = DoTexSubImage(gl, target, level, 0, 0, 0, width, height, depth, packing, zeros.get()); return !error; }
/*static*/ bool TexUnpackSurface::UploadDataSurface(bool isSubImage, WebGLContext* webgl, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width, GLsizei height, gfx::DataSourceSurface* surf, bool isSurfAlphaPremult, GLenum* const out_glError) { gl::GLContext* gl = webgl->GL(); MOZ_ASSERT(gl->IsCurrent()); *out_glError = 0; if (isSurfAlphaPremult != webgl->mPixelStore_PremultiplyAlpha) return false; gl::OriginPos srcOrigin, dstOrigin; OriginsForDOM(webgl, &srcOrigin, &dstOrigin); if (srcOrigin != dstOrigin) return false; // This differs from the raw-data upload in that we choose how we do the unpack. // (alignment, etc.) // Uploading RGBX as RGBA and blitting to RGB is faster than repacking RGBX into // RGB on the CPU. However, this is optimization is out-of-scope for now. static const webgl::DriverUnpackInfo kInfoBGRA = { LOCAL_GL_BGRA, LOCAL_GL_BGRA, LOCAL_GL_UNSIGNED_BYTE, }; const webgl::DriverUnpackInfo* chosenDUI = nullptr; switch (surf->GetFormat()) { case gfx::SurfaceFormat::B8G8R8A8: if (SupportsBGRA(gl) && dui->internalFormat == LOCAL_GL_RGBA && dui->unpackFormat == LOCAL_GL_RGBA && dui->unpackType == LOCAL_GL_UNSIGNED_BYTE) { chosenDUI = &kInfoBGRA; } break; case gfx::SurfaceFormat::R8G8B8A8: if (dui->unpackFormat == LOCAL_GL_RGBA && dui->unpackType == LOCAL_GL_UNSIGNED_BYTE) { chosenDUI = dui; } break; case gfx::SurfaceFormat::R5G6B5_UINT16: if (dui->unpackFormat == LOCAL_GL_RGB && dui->unpackType == LOCAL_GL_UNSIGNED_SHORT_5_6_5) { chosenDUI = dui; } break; default: break; } if (!chosenDUI) return false; gfx::DataSourceSurface::ScopedMap map(surf, gfx::DataSourceSurface::MapType::READ); if (!map.IsMapped()) return false; const webgl::PackingInfo pi = {chosenDUI->unpackFormat, chosenDUI->unpackType}; const auto bytesPerPixel = webgl::BytesPerPixel(pi); const size_t bytesPerRow = width * bytesPerPixel; const GLint kMaxUnpackAlignment = 8; size_t unpackAlignment; if (!GuessAlignment(map.GetData(), bytesPerRow, map.GetStride(), kMaxUnpackAlignment, &unpackAlignment)) { return false; // TODO: Consider using UNPACK_ settings to set the stride based on the too-large // alignment used for some SourceSurfaces. (D2D allegedy likes alignment=16) } MOZ_ALWAYS_TRUE( webgl->gl->MakeCurrent() ); ScopedUnpackReset scopedReset(webgl); gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, unpackAlignment); const GLsizei depth = 1; GLenum error = DoTexOrSubImage(isSubImage, gl, target.get(), level, chosenDUI, xOffset, yOffset, zOffset, width, height, depth, map.GetData()); if (error) { *out_glError = error; return false; } return true; }
static bool ZeroTextureData(const WebGLContext* webgl, GLuint tex, TexImageTarget target, uint32_t level, const webgl::FormatUsageInfo* usage, uint32_t width, uint32_t height, uint32_t depth) { // This has two usecases: // 1. Lazy zeroing of uninitialized textures: // a. Before draw. // b. Before partial upload. (TexStorage + TexSubImage) // 2. Zero subrects from out-of-bounds blits. (CopyTex(Sub)Image) // We have no sympathy for any of these cases. // "Doctor, it hurts when I do this!" "Well don't do that!" const auto targetStr = EnumString(target.get()); webgl->GeneratePerfWarning( "Tex image %s level %u is incurring lazy initialization.", targetStr.c_str(), level); gl::GLContext* gl = webgl->GL(); GLenum scopeBindTarget; switch (target.get()) { case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: scopeBindTarget = LOCAL_GL_TEXTURE_CUBE_MAP; break; default: scopeBindTarget = target.get(); break; } const gl::ScopedBindTexture scopeBindTexture(gl, tex, scopeBindTarget); const auto& compression = usage->format->compression; if (compression) { auto sizedFormat = usage->format->sizedFormat; MOZ_RELEASE_ASSERT(sizedFormat, "GFX: texture sized format not set"); const auto fnSizeInBlocks = [](CheckedUint32 pixels, uint8_t pixelsPerBlock) { return RoundUpToMultipleOf(pixels, pixelsPerBlock) / pixelsPerBlock; }; const auto widthBlocks = fnSizeInBlocks(width, compression->blockWidth); const auto heightBlocks = fnSizeInBlocks(height, compression->blockHeight); CheckedUint32 checkedByteCount = compression->bytesPerBlock; checkedByteCount *= widthBlocks; checkedByteCount *= heightBlocks; checkedByteCount *= depth; if (!checkedByteCount.isValid()) return false; const size_t byteCount = checkedByteCount.value(); UniqueBuffer zeros = calloc(1, byteCount); if (!zeros) return false; ScopedUnpackReset scopedReset(webgl); gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with // striding it well. const auto error = DoCompressedTexSubImage(gl, target.get(), level, 0, 0, 0, width, height, depth, sizedFormat, byteCount, zeros.get()); return !error; } const auto driverUnpackInfo = usage->idealUnpack; MOZ_RELEASE_ASSERT(driverUnpackInfo, "GFX: ideal unpack info not set."); if (usage->format->d) { // ANGLE_depth_texture does not allow uploads, so we have to clear. // (Restriction because of D3D9) // Also, depth resources are cleared to 1.0f and are always renderable, so // just use FB clears. return ClearDepthTexture(*webgl, tex, target, level, usage, depth); } const webgl::PackingInfo packing = driverUnpackInfo->ToPacking(); const auto bytesPerPixel = webgl::BytesPerPixel(packing); CheckedUint32 checkedByteCount = bytesPerPixel; checkedByteCount *= width; checkedByteCount *= height; checkedByteCount *= depth; if (!checkedByteCount.isValid()) return false; const size_t byteCount = checkedByteCount.value(); UniqueBuffer zeros = calloc(1, byteCount); if (!zeros) return false; ScopedUnpackReset scopedReset(webgl); gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well. const auto error = DoTexSubImage(gl, target, level, 0, 0, 0, width, height, depth, packing, zeros.get()); return !error; }