diff options
Diffstat (limited to 'libs/hwui')
126 files changed, 4614 insertions, 11046 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 5dcfa4e102fd..3cce353052f1 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -2,8 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -HWUI_NEW_OPS := true - # Enables fine-grained GLES error checking # If set to true, every GLES call is wrapped & error checked # Has moderate overhead @@ -26,6 +24,7 @@ hwui_src_files := \ renderstate/Stencil.cpp \ renderstate/TextureState.cpp \ renderthread/CanvasContext.cpp \ + renderthread/OpenGLPipeline.cpp \ renderthread/DrawFrameTask.cpp \ renderthread/EglManager.cpp \ renderthread/RenderProxy.cpp \ @@ -45,19 +44,21 @@ hwui_src_files := \ Animator.cpp \ AnimatorManager.cpp \ AssetAtlas.cpp \ + BakedOpDispatcher.cpp \ + BakedOpRenderer.cpp \ + BakedOpState.cpp \ Caches.cpp \ CanvasState.cpp \ ClipArea.cpp \ DamageAccumulator.cpp \ - DeferredDisplayList.cpp \ DeferredLayerUpdater.cpp \ DeviceInfo.cpp \ DisplayList.cpp \ - DisplayListCanvas.cpp \ Dither.cpp \ Extensions.cpp \ FboCache.cpp \ FontRenderer.cpp \ + FrameBuilder.cpp \ FrameInfo.cpp \ FrameInfoVisualizer.cpp \ GammaFontRenderer.cpp \ @@ -68,23 +69,24 @@ hwui_src_files := \ Interpolator.cpp \ JankTracker.cpp \ Layer.cpp \ - LayerCache.cpp \ + LayerBuilder.cpp \ LayerRenderer.cpp \ LayerUpdateQueue.cpp \ Matrix.cpp \ - OpenGLRenderer.cpp \ + OpDumper.cpp \ Patch.cpp \ PatchCache.cpp \ PathCache.cpp \ - PathTessellator.cpp \ PathParser.cpp \ + PathTessellator.cpp \ PixelBuffer.cpp \ Program.cpp \ ProgramCache.cpp \ Properties.cpp \ - PropertyValuesHolder.cpp \ PropertyValuesAnimatorSet.cpp \ + PropertyValuesHolder.cpp \ Readback.cpp \ + RecordingCanvas.cpp \ RenderBufferCache.cpp \ RenderNode.cpp \ RenderProperties.cpp \ @@ -104,10 +106,20 @@ hwui_src_files := \ hwui_test_common_src_files := \ $(call all-cpp-files-under, tests/common/scenes) \ + tests/common/LeakChecker.cpp \ + tests/common/TestListViewSceneBase.cpp \ tests/common/TestContext.cpp \ tests/common/TestScene.cpp \ tests/common/TestUtils.cpp +hwui_debug_common_src_files := \ + debug/wrap_gles.cpp \ + debug/DefaultGlesDriver.cpp \ + debug/GlesErrorCheckWrapper.cpp \ + debug/GlesDriver.cpp \ + debug/FatalBaseDriver.cpp \ + debug/NullGlesDriver.cpp + hwui_cflags := \ -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES \ -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\" \ @@ -117,19 +129,8 @@ hwui_cflags := \ # a problem hwui_cflags += -Wno-free-nonheap-object -ifeq (true, $(HWUI_NEW_OPS)) - hwui_src_files += \ - BakedOpDispatcher.cpp \ - BakedOpRenderer.cpp \ - BakedOpState.cpp \ - FrameBuilder.cpp \ - LayerBuilder.cpp \ - OpDumper.cpp \ - RecordingCanvas.cpp - - hwui_cflags += -DHWUI_NEW_OPS - -endif +# clang's warning is broken, see: https://llvm.org/bugs/show_bug.cgi?id=21629 +hwui_cflags += -Wno-missing-braces ifndef HWUI_COMPILE_SYMBOLS hwui_cflags += -fvisibility=hidden @@ -160,14 +161,6 @@ ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT)) frameworks/rs endif -ifeq (true, $(HWUI_ENABLE_OPENGL_VALIDATION)) - hwui_cflags += -include debug/wrap_gles.h - hwui_src_files += debug/wrap_gles.cpp - hwui_c_includes += frameworks/native/opengl/libs/GLES2 - hwui_cflags += -DDEBUG_OPENGL=3 -endif - - # ------------------------ # static library # ------------------------ @@ -178,6 +171,13 @@ LOCAL_MODULE_CLASS := STATIC_LIBRARIES LOCAL_MODULE := libhwui_static LOCAL_CFLAGS := $(hwui_cflags) LOCAL_SRC_FILES := $(hwui_src_files) + +ifeq (true, $(HWUI_ENABLE_OPENGL_VALIDATION)) + LOCAL_CFLAGS += -include debug/wrap_gles.h + LOCAL_CFLAGS += -DDEBUG_OPENGL=3 + LOCAL_SRC_FILES += $(hwui_debug_common_src_files) +endif + LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include) LOCAL_EXPORT_C_INCLUDE_DIRS := \ $(LOCAL_PATH) \ @@ -193,14 +193,15 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE_CLASS := STATIC_LIBRARIES -LOCAL_MODULE := libhwui_static_null_gpu +LOCAL_MODULE := libhwui_static_debug LOCAL_CFLAGS := \ $(hwui_cflags) \ + -include debug/wrap_gles.h \ -DHWUI_NULL_GPU LOCAL_SRC_FILES := \ $(hwui_src_files) \ - debug/nullegl.cpp \ - debug/nullgles.cpp + $(hwui_debug_common_src_files) \ + debug/nullegl.cpp LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include) LOCAL_EXPORT_C_INCLUDE_DIRS := \ $(LOCAL_PATH) \ @@ -231,49 +232,47 @@ include $(CLEAR_VARS) LOCAL_MODULE := hwui_unit_tests LOCAL_MODULE_TAGS := tests -LOCAL_STATIC_LIBRARIES := libhwui_static_null_gpu +LOCAL_STATIC_LIBRARIES := libgmock libhwui_static_debug LOCAL_SHARED_LIBRARIES := libmemunreachable LOCAL_CFLAGS := \ $(hwui_cflags) \ + -include debug/wrap_gles.h \ -DHWUI_NULL_GPU LOCAL_C_INCLUDES := $(hwui_c_includes) LOCAL_SRC_FILES += \ $(hwui_test_common_src_files) \ tests/unit/main.cpp \ + tests/unit/BakedOpDispatcherTests.cpp \ + tests/unit/BakedOpRendererTests.cpp \ + tests/unit/BakedOpStateTests.cpp \ tests/unit/CanvasStateTests.cpp \ tests/unit/ClipAreaTests.cpp \ tests/unit/DamageAccumulatorTests.cpp \ tests/unit/DeviceInfoTests.cpp \ tests/unit/FatVectorTests.cpp \ tests/unit/FontRendererTests.cpp \ + tests/unit/FrameBuilderTests.cpp \ tests/unit/GlopBuilderTests.cpp \ tests/unit/GpuMemoryTrackerTests.cpp \ tests/unit/GradientCacheTests.cpp \ tests/unit/LayerUpdateQueueTests.cpp \ + tests/unit/LeakCheckTests.cpp \ tests/unit/LinearAllocatorTests.cpp \ tests/unit/MatrixTests.cpp \ + tests/unit/MeshStateTests.cpp \ tests/unit/OffscreenBufferPoolTests.cpp \ + tests/unit/OpDumperTests.cpp \ + tests/unit/RecordingCanvasTests.cpp \ tests/unit/RenderNodeTests.cpp \ tests/unit/RenderPropertiesTests.cpp \ tests/unit/SkiaBehaviorTests.cpp \ + tests/unit/SkiaCanvasTests.cpp \ tests/unit/SnapshotTests.cpp \ tests/unit/StringUtilsTests.cpp \ tests/unit/TestUtilsTests.cpp \ tests/unit/TextDropShadowCacheTests.cpp \ - tests/unit/VectorDrawableTests.cpp - -ifeq (true, $(HWUI_NEW_OPS)) - LOCAL_SRC_FILES += \ - tests/unit/BakedOpDispatcherTests.cpp \ - tests/unit/BakedOpRendererTests.cpp \ - tests/unit/BakedOpStateTests.cpp \ - tests/unit/FrameBuilderTests.cpp \ - tests/unit/LeakCheckTests.cpp \ - tests/unit/OpDumperTests.cpp \ - tests/unit/RecordingCanvasTests.cpp \ - tests/unit/SkiaCanvasTests.cpp -endif + tests/unit/VectorDrawableTests.cpp \ include $(LOCAL_PATH)/hwui_static_deps.mk include $(BUILD_NATIVE_TEST) @@ -294,8 +293,10 @@ LOCAL_MODULE_STEM_64 := hwuitest64 LOCAL_CFLAGS := $(hwui_cflags) LOCAL_C_INCLUDES := $(hwui_c_includes) -# set to libhwui_static_null_gpu to skip actual GL commands +# set to libhwui_static_debug to skip actual GL commands LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static +LOCAL_SHARED_LIBRARIES := libmemunreachable +LOCAL_STATIC_LIBRARIES := libgoogle-benchmark LOCAL_SRC_FILES += \ $(hwui_test_common_src_files) \ @@ -310,36 +311,29 @@ include $(BUILD_EXECUTABLE) # --------------------- include $(CLEAR_VARS) -LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/local/tmp LOCAL_MODULE:= hwuimicro LOCAL_MODULE_TAGS := tests -LOCAL_MODULE_CLASS := EXECUTABLES -LOCAL_MULTILIB := both -LOCAL_MODULE_STEM_32 := hwuimicro -LOCAL_MODULE_STEM_64 := hwuimicro64 LOCAL_CFLAGS := \ $(hwui_cflags) \ + -include debug/wrap_gles.h \ -DHWUI_NULL_GPU LOCAL_C_INCLUDES := $(hwui_c_includes) -LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_null_gpu -LOCAL_STATIC_LIBRARIES := libgoogle-benchmark +LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_debug +LOCAL_SHARED_LIBRARIES := libmemunreachable LOCAL_SRC_FILES += \ $(hwui_test_common_src_files) \ tests/microbench/main.cpp \ tests/microbench/DisplayListCanvasBench.cpp \ tests/microbench/FontBench.cpp \ + tests/microbench/FrameBuilderBench.cpp \ tests/microbench/LinearAllocatorBench.cpp \ tests/microbench/PathParserBench.cpp \ tests/microbench/ShadowBench.cpp \ tests/microbench/TaskManagerBench.cpp -ifeq (true, $(HWUI_NEW_OPS)) - LOCAL_SRC_FILES += \ - tests/microbench/FrameBuilderBench.cpp -endif include $(LOCAL_PATH)/hwui_static_deps.mk -include $(BUILD_EXECUTABLE) +include $(BUILD_NATIVE_BENCHMARK) diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 949ad450d5f7..ef81a522c050 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -68,8 +68,6 @@ bool Caches::init() { mRegionMesh = nullptr; mProgram = nullptr; - patchCache.init(); - mInitialized = true; mPixelBufferState = new PixelBufferState(); @@ -165,17 +163,15 @@ void Caches::dumpMemoryUsage(String8 &log) { log.appendFormat("Current memory usage / total memory usage (bytes):\n"); log.appendFormat(" TextureCache %8d / %8d\n", textureCache.getSize(), textureCache.getMaxSize()); - log.appendFormat(" LayerCache %8d / %8d (numLayers = %zu)\n", - layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount()); if (mRenderState) { int memused = 0; for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin(); it != mRenderState->mActiveLayers.end(); it++) { const Layer* layer = *it; - log.appendFormat(" Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n", + log.appendFormat(" Layer size %dx%d; texid=%u refs=%d\n", layer->getWidth(), layer->getHeight(), - layer->isTextureLayer(), layer->getTextureId(), - layer->getFbo(), layer->getStrongCount()); + layer->getTextureId(), + layer->getStrongCount()); memused += layer->getWidth() * layer->getHeight() * 4; } log.appendFormat(" Layers total %8d (numLayers = %zu)\n", @@ -250,7 +246,6 @@ void Caches::flush(FlushMode mode) { tessellationCache.clear(); // fall through case FlushMode::Layers: - layerCache.clear(); renderBufferCache.clear(); break; } diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index eac9359beab3..fe9411d8bb3f 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_CACHES_H -#define ANDROID_HWUI_CACHES_H +#pragma once #include "AssetAtlas.h" #include "Dither.h" @@ -23,7 +22,6 @@ #include "FboCache.h" #include "GammaFontRenderer.h" #include "GradientCache.h" -#include "LayerCache.h" #include "PatchCache.h" #include "ProgramCache.h" #include "PathCache.h" @@ -146,7 +144,6 @@ private: Extensions mExtensions; public: TextureCache textureCache; - LayerCache layerCache; RenderBufferCache renderBufferCache; GradientCache gradientCache; PatchCache patchCache; @@ -205,5 +202,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_CACHES_H diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp index e2149d1e4a69..7e2c28c5eb41 100644 --- a/libs/hwui/CanvasState.cpp +++ b/libs/hwui/CanvasState.cpp @@ -23,8 +23,7 @@ namespace uirenderer { CanvasState::CanvasState(CanvasStateClient& renderer) - : mDirtyClip(false) - , mWidth(-1) + : mWidth(-1) , mHeight(-1) , mSaveCount(1) , mCanvas(renderer) @@ -205,19 +204,16 @@ void CanvasState::concatMatrix(const Matrix4& matrix) { bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { mSnapshot->clip(Rect(left, top, right, bottom), op); - mDirtyClip = true; return !mSnapshot->clipIsEmpty(); } bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) { mSnapshot->clipPath(*path, op); - mDirtyClip = true; return !mSnapshot->clipIsEmpty(); } bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) { mSnapshot->clipRegionTransformed(*region, op); - mDirtyClip = true; return !mSnapshot->clipIsEmpty(); } @@ -236,15 +232,6 @@ void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* } } -void CanvasState::setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius, bool highPriority) { - mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority); -} - -void CanvasState::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) { - mSnapshot->setProjectionPathMask(allocator, path); -} - /////////////////////////////////////////////////////////////////////////////// // Quick Rejection /////////////////////////////////////////////////////////////////////////////// @@ -263,7 +250,7 @@ bool CanvasState::calculateQuickRejectForScissor(float left, float top, float right, float bottom, bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const { - if (mSnapshot->isIgnored() || bottom <= top || right <= left) { + if (bottom <= top || right <= left) { return true; } @@ -291,7 +278,7 @@ bool CanvasState::calculateQuickRejectForScissor(float left, float top, bool CanvasState::quickRejectConservative(float left, float top, float right, float bottom) const { - if (mSnapshot->isIgnored() || bottom <= top || right <= left) { + if (bottom <= top || right <= left) { return true; } diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h index b9e87ae5595d..ba260d1ab88e 100644 --- a/libs/hwui/CanvasState.h +++ b/libs/hwui/CanvasState.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_CANVAS_STATE_H -#define ANDROID_HWUI_CANVAS_STATE_H +#pragma once #include "Snapshot.h" @@ -62,11 +61,11 @@ public: * Renderer interface. Drawing and recording classes that include a CanvasState will have * different use cases: * - * Drawing code maintaining canvas state (i.e. OpenGLRenderer) can query attributes (such as + * Drawing code maintaining canvas state (e.g. FrameBuilder) can query attributes (such as * transform) or hook into changes (e.g. save/restore) with minimal surface area for manipulating * the stack itself. * - * Recording code maintaining canvas state (i.e. DisplayListCanvas) can both record and pass + * Recording code maintaining canvas state (e.g. RecordingCanvas) can both record and pass * through state operations to CanvasState, so that not only will querying operations work * (getClip/Matrix), but so that quickRejection can also be used. */ @@ -134,8 +133,12 @@ public: */ void setClippingOutline(LinearAllocator& allocator, const Outline* outline); void setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius, bool highPriority = true); - void setProjectionPathMask(LinearAllocator& allocator, const SkPath* path); + const Rect& rect, float radius, bool highPriority = true) { + mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority); + } + void setProjectionPathMask(const SkPath* path) { + mSnapshot->setProjectionPathMask(path); + } /** * Returns true if drawing in the rectangle (left, top, right, bottom) @@ -145,19 +148,12 @@ public: bool calculateQuickRejectForScissor(float left, float top, float right, float bottom, bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const; - void setDirtyClip(bool opaque) { mDirtyClip = opaque; } - bool getDirtyClip() const { return mDirtyClip; } - void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; } - void setEmpty(bool value) { mSnapshot->empty = value; } - void setInvisible(bool value) { mSnapshot->invisible = value; } inline const mat4* currentTransform() const { return currentSnapshot()->transform; } inline const Rect& currentRenderTargetClip() const { return currentSnapshot()->getRenderTargetClip(); } - inline Region* currentRegion() const { return currentSnapshot()->region; } inline int currentFlags() const { return currentSnapshot()->flags; } const Vector3& currentLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); } - inline bool currentlyIgnored() const { return currentSnapshot()->isIgnored(); } int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); } int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); } int getWidth() const { return mWidth; } @@ -173,10 +169,6 @@ private: void freeSnapshot(Snapshot* snapshot); void freeAllSnapshots(); - /// indicates that the clip has been changed since the last time it was consumed - // TODO: delete when switching to HWUI_NEW_OPS - bool mDirtyClip; - /// Dimensions of the drawing surface int mWidth, mHeight; @@ -201,5 +193,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_CANVAS_STATE_H diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h index 748edef730b7..e29699d0faf4 100644 --- a/libs/hwui/Debug.h +++ b/libs/hwui/Debug.h @@ -98,6 +98,9 @@ // Turn on to enable debugging shadow #define DEBUG_SHADOW 0 +// Turn on to enable debugging vector drawable +#define DEBUG_VECTOR_DRAWABLE 0 + #if DEBUG_INIT #define INIT_LOGD(...) ALOGD(__VA_ARGS__) #else diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp deleted file mode 100644 index 689179dd8fb4..000000000000 --- a/libs/hwui/DeferredDisplayList.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <utils/Trace.h> -#include <ui/Rect.h> -#include <ui/Region.h> - -#include "Caches.h" -#include "Debug.h" -#include "DeferredDisplayList.h" -#include "DisplayListOp.h" -#include "OpenGLRenderer.h" -#include "Properties.h" -#include "utils/MathUtils.h" - -#if DEBUG_DEFER - #define DEFER_LOGD(...) ALOGD(__VA_ARGS__) -#else - #define DEFER_LOGD(...) -#endif - -namespace android { -namespace uirenderer { - -// Depth of the save stack at the beginning of batch playback at flush time -#define FLUSH_SAVE_STACK_DEPTH 2 - -#define DEBUG_COLOR_BARRIER 0x1f000000 -#define DEBUG_COLOR_MERGEDBATCH 0x5f7f7fff -#define DEBUG_COLOR_MERGEDBATCH_SOLO 0x5f7fff7f - -static bool avoidOverdraw() { - // Don't avoid overdraw when visualizing it, since that makes it harder to - // debug where it's coming from, and when the problem occurs. - return !Properties::debugOverdraw; -}; - -///////////////////////////////////////////////////////////////////////////////// -// Operation Batches -///////////////////////////////////////////////////////////////////////////////// - -class Batch { -public: - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) = 0; - virtual ~Batch() {} - virtual bool purelyDrawBatch() { return false; } - virtual bool coversBounds(const Rect& bounds) { return false; } -}; - -class DrawBatch : public Batch { -public: - explicit DrawBatch(const DeferInfo& deferInfo) : mAllOpsOpaque(true), - mBatchId(deferInfo.batchId), mMergeId(deferInfo.mergeId) { - mOps.clear(); - } - - virtual ~DrawBatch() { mOps.clear(); } - - virtual void add(DrawOp* op, const DeferredDisplayState* state, bool opaqueOverBounds) { - // NOTE: ignore empty bounds special case, since we don't merge across those ops - mBounds.unionWith(state->mBounds); - mAllOpsOpaque &= opaqueOverBounds; - mOps.push_back(OpStatePair(op, state)); - } - - bool intersects(const Rect& rect) { - if (!rect.intersects(mBounds)) return false; - - for (unsigned int i = 0; i < mOps.size(); i++) { - if (rect.intersects(mOps[i].state->mBounds)) { -#if DEBUG_DEFER - DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i].op, - mOps[i].state->mBounds.left, mOps[i].state->mBounds.top, - mOps[i].state->mBounds.right, mOps[i].state->mBounds.bottom); - mOps[i].op->output(2); -#endif - return true; - } - } - return false; - } - - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override { - DEFER_LOGD("%d replaying DrawBatch %p, with %d ops (batch id %x, merge id %p)", - index, this, mOps.size(), getBatchId(), getMergeId()); - - for (unsigned int i = 0; i < mOps.size(); i++) { - DrawOp* op = mOps[i].op; - const DeferredDisplayState* state = mOps[i].state; - renderer.restoreDisplayState(*state); - -#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS - renderer.eventMark(op->name()); -#endif - op->applyDraw(renderer, dirty); - -#if DEBUG_MERGE_BEHAVIOR - const Rect& bounds = state->mBounds; - int batchColor = 0x1f000000; - if (getBatchId() & 0x1) batchColor |= 0x0000ff; - if (getBatchId() & 0x2) batchColor |= 0x00ff00; - if (getBatchId() & 0x4) batchColor |= 0xff0000; - renderer.drawScreenSpaceColorRect(bounds.left, bounds.top, bounds.right, bounds.bottom, - batchColor); -#endif - } - } - - virtual bool purelyDrawBatch() override { return true; } - - virtual bool coversBounds(const Rect& bounds) override { - if (CC_LIKELY(!mAllOpsOpaque || !mBounds.contains(bounds) || count() == 1)) return false; - - Region uncovered(android::Rect(bounds.left, bounds.top, bounds.right, bounds.bottom)); - for (unsigned int i = 0; i < mOps.size(); i++) { - const Rect &r = mOps[i].state->mBounds; - uncovered.subtractSelf(android::Rect(r.left, r.top, r.right, r.bottom)); - } - return uncovered.isEmpty(); - } - - inline int getBatchId() const { return mBatchId; } - inline mergeid_t getMergeId() const { return mMergeId; } - inline int count() const { return mOps.size(); } - -protected: - std::vector<OpStatePair> mOps; - Rect mBounds; // union of bounds of contained ops -private: - bool mAllOpsOpaque; - int mBatchId; - mergeid_t mMergeId; -}; - -class MergingDrawBatch : public DrawBatch { -public: - MergingDrawBatch(DeferInfo& deferInfo, int width, int height) : - DrawBatch(deferInfo), mClipRect(width, height), - mClipSideFlags(kClipSide_None) {} - - /* - * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds - * and clip side flags. Positive bounds delta means new bounds fit in old. - */ - static inline bool checkSide(const int currentFlags, const int newFlags, const int side, - float boundsDelta) { - bool currentClipExists = currentFlags & side; - bool newClipExists = newFlags & side; - - // if current is clipped, we must be able to fit new bounds in current - if (boundsDelta > 0 && currentClipExists) return false; - - // if new is clipped, we must be able to fit current bounds in new - if (boundsDelta < 0 && newClipExists) return false; - - return true; - } - - /* - * Checks if a (mergeable) op can be merged into this batch - * - * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is - * important to consider all paint attributes used in the draw calls in deciding both a) if an - * op tries to merge at all, and b) if the op can merge with another set of ops - * - * False positives can lead to information from the paints of subsequent merged operations being - * dropped, so we make simplifying qualifications on the ops that can merge, per op type. - */ - bool canMergeWith(const DrawOp* op, const DeferredDisplayState* state) { - bool isTextBatch = getBatchId() == DeferredDisplayList::kOpBatch_Text || - getBatchId() == DeferredDisplayList::kOpBatch_ColorText; - - // Overlapping other operations is only allowed for text without shadow. For other ops, - // multiDraw isn't guaranteed to overdraw correctly - if (!isTextBatch || op->hasTextShadow()) { - if (intersects(state->mBounds)) return false; - } - const DeferredDisplayState* lhs = state; - const DeferredDisplayState* rhs = mOps[0].state; - - if (!MathUtils::areEqual(lhs->mAlpha, rhs->mAlpha)) return false; - - // Identical round rect clip state means both ops will clip in the same way, or not at all. - // As the state objects are const, we can compare their pointers to determine mergeability - if (lhs->mRoundRectClipState != rhs->mRoundRectClipState) return false; - if (lhs->mProjectionPathMask != rhs->mProjectionPathMask) return false; - - /* Clipping compatibility check - * - * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its - * clip for that side. - */ - const int currentFlags = mClipSideFlags; - const int newFlags = state->mClipSideFlags; - if (currentFlags != kClipSide_None || newFlags != kClipSide_None) { - const Rect& opBounds = state->mBounds; - float boundsDelta = mBounds.left - opBounds.left; - if (!checkSide(currentFlags, newFlags, kClipSide_Left, boundsDelta)) return false; - boundsDelta = mBounds.top - opBounds.top; - if (!checkSide(currentFlags, newFlags, kClipSide_Top, boundsDelta)) return false; - - // right and bottom delta calculation reversed to account for direction - boundsDelta = opBounds.right - mBounds.right; - if (!checkSide(currentFlags, newFlags, kClipSide_Right, boundsDelta)) return false; - boundsDelta = opBounds.bottom - mBounds.bottom; - if (!checkSide(currentFlags, newFlags, kClipSide_Bottom, boundsDelta)) return false; - } - - // if paints are equal, then modifiers + paint attribs don't need to be compared - if (op->mPaint == mOps[0].op->mPaint) return true; - - if (PaintUtils::getAlphaDirect(op->mPaint) - != PaintUtils::getAlphaDirect(mOps[0].op->mPaint)) { - return false; - } - - if (op->mPaint && mOps[0].op->mPaint && - op->mPaint->getColorFilter() != mOps[0].op->mPaint->getColorFilter()) { - return false; - } - - if (op->mPaint && mOps[0].op->mPaint && - op->mPaint->getShader() != mOps[0].op->mPaint->getShader()) { - return false; - } - - return true; - } - - virtual void add(DrawOp* op, const DeferredDisplayState* state, - bool opaqueOverBounds) override { - DrawBatch::add(op, state, opaqueOverBounds); - - const int newClipSideFlags = state->mClipSideFlags; - mClipSideFlags |= newClipSideFlags; - if (newClipSideFlags & kClipSide_Left) mClipRect.left = state->mClip.left; - if (newClipSideFlags & kClipSide_Top) mClipRect.top = state->mClip.top; - if (newClipSideFlags & kClipSide_Right) mClipRect.right = state->mClip.right; - if (newClipSideFlags & kClipSide_Bottom) mClipRect.bottom = state->mClip.bottom; - } - - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override { - DEFER_LOGD("%d replaying MergingDrawBatch %p, with %d ops," - " clip flags %x (batch id %x, merge id %p)", - index, this, mOps.size(), mClipSideFlags, getBatchId(), getMergeId()); - if (mOps.size() == 1) { - DrawBatch::replay(renderer, dirty, -1); - return; - } - - // clipping in the merged case is done ahead of time since all ops share the clip (if any) - renderer.setupMergedMultiDraw(mClipSideFlags ? &mClipRect : nullptr); - - DrawOp* op = mOps[0].op; -#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS - renderer.eventMark("multiDraw"); - renderer.eventMark(op->name()); -#endif - op->multiDraw(renderer, dirty, mOps, mBounds); - -#if DEBUG_MERGE_BEHAVIOR - renderer.drawScreenSpaceColorRect(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom, - DEBUG_COLOR_MERGEDBATCH); -#endif - } - -private: - /* - * Contains the effective clip rect shared by all merged ops. Initialized to the layer viewport, - * it will shrink if an op must be clipped on a certain side. The clipped sides are reflected in - * mClipSideFlags. - */ - Rect mClipRect; - int mClipSideFlags; -}; - -class StateOpBatch : public Batch { -public: - // creates a single operation batch - StateOpBatch(const StateOp* op, const DeferredDisplayState* state) : mOp(op), mState(state) {} - - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override { - DEFER_LOGD("replaying state op batch %p", this); - renderer.restoreDisplayState(*mState); - - // use invalid save count because it won't be used at flush time - RestoreToCountOp is the - // only one to use it, and we don't use that class at flush time, instead calling - // renderer.restoreToCount directly - int saveCount = -1; - mOp->applyState(renderer, saveCount); - } - -private: - const StateOp* mOp; - const DeferredDisplayState* mState; -}; - -class RestoreToCountBatch : public Batch { -public: - RestoreToCountBatch(const StateOp* op, const DeferredDisplayState* state, int restoreCount) : - mState(state), mRestoreCount(restoreCount) {} - - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override { - DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount); - - renderer.restoreDisplayState(*mState); - renderer.restoreToCount(mRestoreCount); - } - -private: - // we use the state storage for the RestoreToCountOp, but don't replay the op itself - const DeferredDisplayState* mState; - - /* - * The count used here represents the flush() time saveCount. This is as opposed to the - * DisplayList record time, or defer() time values (which are RestoreToCountOp's mCount, and - * (saveCount + mCount) respectively). Since the count is different from the original - * RestoreToCountOp, we don't store a pointer to the op, as elsewhere. - */ - const int mRestoreCount; -}; - -#if DEBUG_MERGE_BEHAVIOR -class BarrierDebugBatch : public Batch { - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) { - renderer.drawScreenSpaceColorRect(0, 0, 10000, 10000, DEBUG_COLOR_BARRIER); - } -}; -#endif - -///////////////////////////////////////////////////////////////////////////////// -// DeferredDisplayList -///////////////////////////////////////////////////////////////////////////////// - -void DeferredDisplayList::resetBatchingState() { - for (int i = 0; i < kOpBatch_Count; i++) { - mBatchLookup[i] = nullptr; - mMergingBatches[i].clear(); - } -#if DEBUG_MERGE_BEHAVIOR - if (mBatches.size() != 0) { - mBatches.add(new BarrierDebugBatch()); - } -#endif - mEarliestBatchIndex = mBatches.size(); -} - -void DeferredDisplayList::clear() { - resetBatchingState(); - mComplexClipStackStart = -1; - - for (unsigned int i = 0; i < mBatches.size(); i++) { - delete mBatches[i]; - } - mBatches.clear(); - mSaveStack.clear(); - mEarliestBatchIndex = 0; - mEarliestUnclearedIndex = 0; -} - -///////////////////////////////////////////////////////////////////////////////// -// Operation adding -///////////////////////////////////////////////////////////////////////////////// - -int DeferredDisplayList::getStateOpDeferFlags() const { - // For both clipOp and save(Layer)Op, we don't want to save drawing info, and only want to save - // the clip if we aren't recording a complex clip (and can thus trust it to be a rect) - return recordingComplexClip() ? 0 : kStateDeferFlag_Clip; -} - -int DeferredDisplayList::getDrawOpDeferFlags() const { - return kStateDeferFlag_Draw | getStateOpDeferFlags(); -} - -/** - * When an clipping operation occurs that could cause a complex clip, record the operation and all - * subsequent clipOps, save/restores (if the clip flag is set). During a flush, instead of loading - * the clip from deferred state, we play back all of the relevant state operations that generated - * the complex clip. - * - * Note that we don't need to record the associated restore operation, since operations at defer - * time record whether they should store the renderer's current clip - */ -void DeferredDisplayList::addClip(OpenGLRenderer& renderer, ClipOp* op) { - if (recordingComplexClip() || op->canCauseComplexClip() || !renderer.hasRectToRectTransform()) { - DEFER_LOGD("%p Received complex clip operation %p", this, op); - - // NOTE: defer clip op before setting mComplexClipStackStart so previous clip is recorded - storeStateOpBarrier(renderer, op); - - if (!recordingComplexClip()) { - mComplexClipStackStart = renderer.getSaveCount() - 1; - DEFER_LOGD(" Starting complex clip region, start is %d", mComplexClipStackStart); - } - } -} - -/** - * For now, we record save layer operations as barriers in the batch list, preventing drawing - * operations from reordering around the saveLayer and it's associated restore() - * - * In the future, we should send saveLayer commands (if they can be played out of order) and their - * contained drawing operations to a seperate list of batches, so that they may draw at the - * beginning of the frame. This would avoid targetting and removing an FBO in the middle of a frame. - * - * saveLayer operations should be pulled to the beginning of the frame if the canvas doesn't have a - * complex clip, and if the flags (SaveFlags::Clip & SaveFlags::ClipToLayer) are set. - */ -void DeferredDisplayList::addSaveLayer(OpenGLRenderer& renderer, - SaveLayerOp* op, int newSaveCount) { - DEFER_LOGD("%p adding saveLayerOp %p, flags %x, new count %d", - this, op, op->getFlags(), newSaveCount); - - storeStateOpBarrier(renderer, op); - mSaveStack.push_back(newSaveCount); -} - -/** - * Takes save op and it's return value - the new save count - and stores it into the stream as a - * barrier if it's needed to properly modify a complex clip - */ -void DeferredDisplayList::addSave(OpenGLRenderer& renderer, SaveOp* op, int newSaveCount) { - int saveFlags = op->getFlags(); - DEFER_LOGD("%p adding saveOp %p, flags %x, new count %d", this, op, saveFlags, newSaveCount); - - if (recordingComplexClip() && (saveFlags & SaveFlags::Clip)) { - // store and replay the save operation, as it may be needed to correctly playback the clip - DEFER_LOGD(" adding save barrier with new save count %d", newSaveCount); - storeStateOpBarrier(renderer, op); - mSaveStack.push_back(newSaveCount); - } -} - -/** - * saveLayer() commands must be associated with a restoreToCount batch that will clean up and draw - * the layer in the deferred list - * - * other save() commands which occur as children of a snapshot with complex clip will be deferred, - * and must be restored - * - * Either will act as a barrier to draw operation reordering, as we want to play back layer - * save/restore and complex canvas modifications (including save/restore) in order. - */ -void DeferredDisplayList::addRestoreToCount(OpenGLRenderer& renderer, StateOp* op, - int newSaveCount) { - DEFER_LOGD("%p addRestoreToCount %d", this, newSaveCount); - - if (recordingComplexClip() && newSaveCount <= mComplexClipStackStart) { - mComplexClipStackStart = -1; - resetBatchingState(); - } - - if (mSaveStack.empty() || newSaveCount > mSaveStack.back()) { - return; - } - - while (!mSaveStack.empty() && mSaveStack.back() >= newSaveCount) mSaveStack.pop_back(); - - storeRestoreToCountBarrier(renderer, op, mSaveStack.size() + FLUSH_SAVE_STACK_DEPTH); -} - -void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) { - /* 1: op calculates local bounds */ - DeferredDisplayState* const state = createState(); - if (op->getLocalBounds(state->mBounds)) { - if (state->mBounds.isEmpty()) { - // valid empty bounds, don't bother deferring - tryRecycleState(state); - return; - } - } else { - state->mBounds.setEmpty(); - } - - /* 2: renderer calculates global bounds + stores state */ - if (renderer.storeDisplayState(*state, getDrawOpDeferFlags())) { - tryRecycleState(state); - return; // quick rejected - } - - /* 3: ask op for defer info, given renderer state */ - DeferInfo deferInfo; - op->onDefer(renderer, deferInfo, *state); - - // complex clip has a complex set of expectations on the renderer state - for now, avoid taking - // the merge path in those cases - deferInfo.mergeable &= !recordingComplexClip(); - deferInfo.opaqueOverBounds &= !recordingComplexClip() - && mSaveStack.empty() - && !state->mRoundRectClipState; - - if (CC_LIKELY(avoidOverdraw()) && mBatches.size() && - state->mClipSideFlags != kClipSide_ConservativeFull && - deferInfo.opaqueOverBounds && state->mBounds.contains(mBounds)) { - // avoid overdraw by resetting drawing state + discarding drawing ops - discardDrawingBatches(mBatches.size() - 1); - resetBatchingState(); - } - - if (CC_UNLIKELY(Properties::drawReorderDisabled)) { - // TODO: elegant way to reuse batches? - DrawBatch* b = new DrawBatch(deferInfo); - b->add(op, state, deferInfo.opaqueOverBounds); - mBatches.push_back(b); - return; - } - - // find the latest batch of the new op's type, and try to merge the new op into it - DrawBatch* targetBatch = nullptr; - - // insertion point of a new batch, will hopefully be immediately after similar batch - // (eventually, should be similar shader) - int insertBatchIndex = mBatches.size(); - if (!mBatches.empty()) { - if (state->mBounds.isEmpty()) { - // don't know the bounds for op, so create new batch and start from scratch on next op - DrawBatch* b = new DrawBatch(deferInfo); - b->add(op, state, deferInfo.opaqueOverBounds); - mBatches.push_back(b); - resetBatchingState(); -#if DEBUG_DEFER - DEFER_LOGD("Warning: Encountered op with empty bounds, resetting batches"); - op->output(2); -#endif - return; - } - - if (deferInfo.mergeable) { - // Try to merge with any existing batch with same mergeId. - std::unordered_map<mergeid_t, DrawBatch*>& mergingBatch - = mMergingBatches[deferInfo.batchId]; - auto getResult = mergingBatch.find(deferInfo.mergeId); - if (getResult != mergingBatch.end()) { - targetBatch = getResult->second; - if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op, state)) { - targetBatch = nullptr; - } - } - } else { - // join with similar, non-merging batch - targetBatch = (DrawBatch*)mBatchLookup[deferInfo.batchId]; - } - - if (targetBatch || deferInfo.mergeable) { - // iterate back toward target to see if anything drawn since should overlap the new op - // if no target, merging ops still interate to find similar batch to insert after - for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) { - DrawBatch* overBatch = (DrawBatch*)mBatches[i]; - - if (overBatch == targetBatch) break; - - // TODO: also consider shader shared between batch types - if (deferInfo.batchId == overBatch->getBatchId()) { - insertBatchIndex = i + 1; - if (!targetBatch) break; // found insert position, quit - } - - if (overBatch->intersects(state->mBounds)) { - // NOTE: it may be possible to optimize for special cases where two operations - // of the same batch/paint could swap order, such as with a non-mergeable - // (clipped) and a mergeable text operation - targetBatch = nullptr; -#if DEBUG_DEFER - DEFER_LOGD("op couldn't join batch %p, was intersected by batch %d", - targetBatch, i); - op->output(2); -#endif - break; - } - } - } - } - - if (!targetBatch) { - if (deferInfo.mergeable) { - targetBatch = new MergingDrawBatch(deferInfo, - renderer.getViewportWidth(), renderer.getViewportHeight()); - mMergingBatches[deferInfo.batchId].insert( - std::make_pair(deferInfo.mergeId, targetBatch)); - } else { - targetBatch = new DrawBatch(deferInfo); - mBatchLookup[deferInfo.batchId] = targetBatch; - } - - DEFER_LOGD("creating %singBatch %p, bid %x, at %d", - deferInfo.mergeable ? "Merg" : "Draw", - targetBatch, deferInfo.batchId, insertBatchIndex); - mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); - } - - targetBatch->add(op, state, deferInfo.opaqueOverBounds); -} - -void DeferredDisplayList::storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op) { - DEFER_LOGD("%p adding state op barrier at pos %d", this, mBatches.size()); - - DeferredDisplayState* state = createState(); - renderer.storeDisplayState(*state, getStateOpDeferFlags()); - mBatches.push_back(new StateOpBatch(op, state)); - resetBatchingState(); -} - -void DeferredDisplayList::storeRestoreToCountBarrier(OpenGLRenderer& renderer, StateOp* op, - int newSaveCount) { - DEFER_LOGD("%p adding restore to count %d barrier, pos %d", - this, newSaveCount, mBatches.size()); - - // store displayState for the restore operation, as it may be associated with a saveLayer that - // doesn't have SaveFlags::Clip set - DeferredDisplayState* state = createState(); - renderer.storeDisplayState(*state, getStateOpDeferFlags()); - mBatches.push_back(new RestoreToCountBatch(op, state, newSaveCount)); - resetBatchingState(); -} - -///////////////////////////////////////////////////////////////////////////////// -// Replay / flush -///////////////////////////////////////////////////////////////////////////////// - -static void replayBatchList(const std::vector<Batch*>& batchList, - OpenGLRenderer& renderer, Rect& dirty) { - - for (unsigned int i = 0; i < batchList.size(); i++) { - if (batchList[i]) { - batchList[i]->replay(renderer, dirty, i); - } - } - DEFER_LOGD("--flushed, drew %d batches", batchList.size()); -} - -void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) { - ATRACE_NAME("flush drawing commands"); - Caches::getInstance().fontRenderer.endPrecaching(); - - if (isEmpty()) return; // nothing to flush - renderer.restoreToCount(1); - - DEFER_LOGD("--flushing"); - renderer.eventMark("Flush"); - - // save and restore so that reordering doesn't affect final state - renderer.save(SaveFlags::MatrixClip); - - if (CC_LIKELY(avoidOverdraw())) { - for (unsigned int i = 1; i < mBatches.size(); i++) { - if (mBatches[i] && mBatches[i]->coversBounds(mBounds)) { - discardDrawingBatches(i - 1); - } - } - } - // NOTE: depth of the save stack at this point, before playback, should be reflected in - // FLUSH_SAVE_STACK_DEPTH, so that save/restores match up correctly - replayBatchList(mBatches, renderer, dirty); - - renderer.restoreToCount(1); - - DEFER_LOGD("--flush complete, returning %x", status); - clear(); -} - -void DeferredDisplayList::discardDrawingBatches(const unsigned int maxIndex) { - for (unsigned int i = mEarliestUnclearedIndex; i <= maxIndex; i++) { - // leave deferred state ops alone for simplicity (empty save restore pairs may now exist) - if (mBatches[i] && mBatches[i]->purelyDrawBatch()) { - delete mBatches[i]; - mBatches[i] = nullptr; - } - } - mEarliestUnclearedIndex = maxIndex + 1; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h deleted file mode 100644 index 98ccf11b1c2a..000000000000 --- a/libs/hwui/DeferredDisplayList.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H -#define ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H - -#include <unordered_map> - -#include <utils/Errors.h> -#include <utils/LinearAllocator.h> - -#include "Matrix.h" -#include "OpenGLRenderer.h" -#include "Rect.h" - -#include <vector> - -class SkBitmap; - -namespace android { -namespace uirenderer { - -class ClipOp; -class DrawOp; -class SaveOp; -class SaveLayerOp; -class StateOp; - -class DeferredDisplayState; - -class Batch; -class DrawBatch; -class MergingDrawBatch; - -typedef const void* mergeid_t; - -class DeferredDisplayState { -public: - // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped - Rect mBounds; - - // the below are set and used by the OpenGLRenderer at record and deferred playback - bool mClipValid; - Rect mClip; - int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared - mat4 mMatrix; - float mAlpha; - const RoundRectClipState* mRoundRectClipState; - const ProjectionPathMask* mProjectionPathMask; -}; - -class OpStatePair { -public: - OpStatePair() - : op(nullptr), state(nullptr) {} - OpStatePair(DrawOp* newOp, const DeferredDisplayState* newState) - : op(newOp), state(newState) {} - OpStatePair(const OpStatePair& other) - : op(other.op), state(other.state) {} - DrawOp* op; - const DeferredDisplayState* state; -}; - -class DeferredDisplayList { - friend struct DeferStateStruct; // used to give access to allocator -public: - DeferredDisplayList(const Rect& bounds) - : mBounds(bounds) { - clear(); - } - ~DeferredDisplayList() { clear(); } - - enum OpBatchId { - kOpBatch_None = 0, // Don't batch - kOpBatch_Bitmap, - kOpBatch_Patch, - kOpBatch_AlphaVertices, - kOpBatch_Vertices, - kOpBatch_AlphaMaskTexture, - kOpBatch_Text, - kOpBatch_ColorText, - - kOpBatch_Count, // Add other batch ids before this - }; - - bool isEmpty() { return mBatches.empty(); } - - /** - * Plays back all of the draw ops recorded into batches to the renderer. - * Adjusts the state of the renderer as necessary, and restores it when complete - */ - void flush(OpenGLRenderer& renderer, Rect& dirty); - - void addClip(OpenGLRenderer& renderer, ClipOp* op); - void addSaveLayer(OpenGLRenderer& renderer, SaveLayerOp* op, int newSaveCount); - void addSave(OpenGLRenderer& renderer, SaveOp* op, int newSaveCount); - void addRestoreToCount(OpenGLRenderer& renderer, StateOp* op, int newSaveCount); - - /** - * Add a draw op into the DeferredDisplayList, reordering as needed (for performance) if - * disallowReorder is false, respecting draw order when overlaps occur. - */ - void addDrawOp(OpenGLRenderer& renderer, DrawOp* op); - -private: - DeferredDisplayList(const DeferredDisplayList& other); // disallow copy - - DeferredDisplayState* createState() { - return mAllocator.create_trivial<DeferredDisplayState>(); - } - - void tryRecycleState(DeferredDisplayState* state) { - mAllocator.rewindIfLastAlloc(state); - } - - /** - * Resets the batching back-pointers, creating a barrier in the operation stream so that no ops - * added in the future will be inserted into a batch that already exist. - */ - void resetBatchingState(); - - void clear(); - - void storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op); - void storeRestoreToCountBarrier(OpenGLRenderer& renderer, StateOp* op, int newSaveCount); - - bool recordingComplexClip() const { return mComplexClipStackStart >= 0; } - - int getStateOpDeferFlags() const; - int getDrawOpDeferFlags() const; - - void discardDrawingBatches(const unsigned int maxIndex); - - // layer space bounds of rendering - Rect mBounds; - - /** - * At defer time, stores the *defer time* savecount of save/saveLayer ops that were deferred, so - * that when an associated restoreToCount is deferred, it can be recorded as a - * RestoreToCountBatch - */ - std::vector<int> mSaveStack; - int mComplexClipStackStart; - - std::vector<Batch*> mBatches; - - // Maps batch ids to the most recent *non-merging* batch of that id - Batch* mBatchLookup[kOpBatch_Count]; - - // Points to the index after the most recent barrier - int mEarliestBatchIndex; - - // Points to the first index that may contain a pure drawing batch - int mEarliestUnclearedIndex; - - /** - * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen - * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not - * collide, which avoids the need to resolve mergeid collisions. - */ - std::unordered_map<mergeid_t, DrawBatch*> mMergingBatches[kOpBatch_Count]; - - LinearAllocator mAllocator; -}; - -/** - * Struct containing information that instructs the defer - */ -struct DeferInfo { -public: - DeferInfo() : - batchId(DeferredDisplayList::kOpBatch_None), - mergeId((mergeid_t) -1), - mergeable(false), - opaqueOverBounds(false) { - }; - - int batchId; - mergeid_t mergeId; - bool mergeable; - bool opaqueOverBounds; // opaque over bounds in DeferredDisplayState - can skip ops below -}; - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index f833a5405a5c..f13cb8d7d1d7 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -15,11 +15,10 @@ */ #include "DeferredLayerUpdater.h" -#include "OpenGLRenderer.h" - #include "LayerRenderer.h" #include "renderthread/EglManager.h" #include "renderthread/RenderTask.h" +#include "utils/PaintUtils.h" namespace android { namespace uirenderer { @@ -29,8 +28,7 @@ DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer) , mTransform(nullptr) , mNeedsGLContextAttach(false) , mUpdateTexImage(false) - , mLayer(layer) - , mCaches(Caches::getInstance()) { + , mLayer(layer) { mWidth = mLayer->layer.getWidth(); mHeight = mLayer->layer.getHeight(); mBlend = mLayer->isBlend(); @@ -54,7 +52,6 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) { } void DeferredLayerUpdater::apply() { - // These properties are applied the same to both layer types mLayer->setColorFilter(mColorFilter); mLayer->setAlpha(mAlpha, mMode); diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 44a24c840892..389e17d12080 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef DEFERREDLAYERUPDATE_H_ -#define DEFERREDLAYERUPDATE_H_ + +#pragma once #include <cutils/compiler.h> #include <gui/GLConsumer.h> @@ -100,19 +100,15 @@ private: SkColorFilter* mColorFilter; int mAlpha; SkXfermode::Mode mMode; - sp<GLConsumer> mSurfaceTexture; SkMatrix* mTransform; bool mNeedsGLContextAttach; bool mUpdateTexImage; Layer* mLayer; - Caches& mCaches; void doUpdateTexImage(); }; } /* namespace uirenderer */ } /* namespace android */ - -#endif /* DEFERREDLAYERUPDATE_H_ */ diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 28be05c52cfc..ca9e2bd4d3ef 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -21,13 +21,8 @@ #include "Debug.h" #include "DisplayList.h" -#include "RenderNode.h" - -#if HWUI_NEW_OPS #include "RecordedOp.h" -#else -#include "DisplayListOp.h" -#endif +#include "RenderNode.h" namespace android { namespace uirenderer { @@ -45,8 +40,7 @@ DisplayList::DisplayList() , regions(stdAllocator) , referenceHolders(stdAllocator) , functors(stdAllocator) - , vectorDrawables(stdAllocator) - , hasDrawOps(false) { + , vectorDrawables(stdAllocator) { } DisplayList::~DisplayList() { diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index ccf71c6d360b..a8205c854c14 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_DISPLAY_LIST_H -#define ANDROID_HWUI_DISPLAY_LIST_H +#pragma once #include <SkCamera.h> #include <SkMatrix.h> @@ -34,7 +33,6 @@ #include "Debug.h" #include "CanvasProperty.h" -#include "DeferredDisplayList.h" #include "GlFunctorLifecycleListener.h" #include "Matrix.h" #include "RenderProperties.h" @@ -49,72 +47,20 @@ class SkRegion; namespace android { namespace uirenderer { -class DeferredDisplayList; -class DisplayListOp; -class DisplayListCanvas; -class OpenGLRenderer; class Rect; class Layer; -#if HWUI_NEW_OPS struct RecordedOp; struct RenderNodeOp; typedef RecordedOp BaseOpType; typedef RenderNodeOp NodeOpType; -#else -class DrawRenderNodeOp; - -typedef DisplayListOp BaseOpType; -typedef DrawRenderNodeOp NodeOpType; -#endif namespace VectorDrawable { class Tree; }; typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; -/** - * Holds data used in the playback a tree of DisplayLists. - */ -struct PlaybackStateStruct { -protected: - PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator) - : mRenderer(renderer) - , mReplayFlags(replayFlags) - , mAllocator(allocator) {} - -public: - OpenGLRenderer& mRenderer; - const int mReplayFlags; - - // Allocator with the lifetime of a single frame. replay uses an Allocator owned by the struct, - // while defer shares the DeferredDisplayList's Allocator - // TODO: move this allocator to be owned by object with clear frame lifecycle - LinearAllocator * const mAllocator; - - SkPath* allocPathForFrame() { - return mRenderer.allocPathForFrame(); - } -}; - -struct DeferStateStruct : public PlaybackStateStruct { - DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags) - : PlaybackStateStruct(renderer, replayFlags, &(deferredList.mAllocator)), - mDeferredList(deferredList) {} - - DeferredDisplayList& mDeferredList; -}; - -struct ReplayStateStruct : public PlaybackStateStruct { - ReplayStateStruct(OpenGLRenderer& renderer, Rect& dirty, int replayFlags) - : PlaybackStateStruct(renderer, replayFlags, &mReplayAllocator), - mDirty(dirty) {} - - Rect& mDirty; - LinearAllocator mReplayAllocator; -}; - struct FunctorContainer { Functor* functor; GlFunctorLifecycleListener* listener; @@ -124,7 +70,6 @@ struct FunctorContainer { * Data structure that holds the list of commands used in display list stream */ class DisplayList { - friend class DisplayListCanvas; friend class RecordingCanvas; public: struct Chunk { @@ -138,9 +83,9 @@ public: // whether children with non-zero Z in the chunk should be reordered bool reorderChildren; -#if HWUI_NEW_OPS + + // clip at the beginning of a reorder section, applied to reordered children const ClipBase* reorderClip; -#endif }; DisplayList(); @@ -169,11 +114,7 @@ public: return allocator.usedSize(); } bool isEmpty() { -#if HWUI_NEW_OPS return ops.empty(); -#else - return !hasDrawOps; -#endif } private: @@ -203,12 +144,8 @@ private: // gets special treatment exclusive for webview. LsaVector<VectorDrawableRoot*> vectorDrawables; - bool hasDrawOps; // only used if !HWUI_NEW_OPS - void cleanupResources(); }; }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_OPENGL_RENDERER_H diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp deleted file mode 100644 index bec662959f91..000000000000 --- a/libs/hwui/DisplayListCanvas.cpp +++ /dev/null @@ -1,597 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "DisplayListCanvas.h" - -#include "DeferredDisplayList.h" -#include "DeferredLayerUpdater.h" -#include "DisplayListOp.h" -#include "ResourceCache.h" -#include "RenderNode.h" -#include "VectorDrawable.h" -#include "utils/PaintUtils.h" - -#include <SkCamera.h> -#include <SkCanvas.h> - -#include <private/hwui/DrawGlInfo.h> - -namespace android { -namespace uirenderer { - -DisplayListCanvas::DisplayListCanvas(int width, int height) - : mState(*this) - , mResourceCache(ResourceCache::getInstance()) - , mDisplayList(nullptr) - , mTranslateX(0.0f) - , mTranslateY(0.0f) - , mHasDeferredTranslate(false) - , mDeferredBarrierType(kBarrier_None) - , mHighContrastText(false) - , mRestoreSaveCount(-1) { - resetRecording(width, height); -} - -DisplayListCanvas::~DisplayListCanvas() { - LOG_ALWAYS_FATAL_IF(mDisplayList, - "Destroyed a DisplayListCanvas during a record!"); -} - -void DisplayListCanvas::resetRecording(int width, int height) { - LOG_ALWAYS_FATAL_IF(mDisplayList, - "prepareDirty called a second time during a recording!"); - mDisplayList = new DisplayList(); - - mState.initializeSaveStack(width, height, - 0, 0, width, height, Vector3()); - - mDeferredBarrierType = kBarrier_InOrder; - mState.setDirtyClip(false); - mRestoreSaveCount = -1; -} - - -/////////////////////////////////////////////////////////////////////////////// -// Operations -/////////////////////////////////////////////////////////////////////////////// - -DisplayList* DisplayListCanvas::finishRecording() { - flushRestoreToCount(); - flushTranslate(); - - mPaintMap.clear(); - mRegionMap.clear(); - mPathMap.clear(); - DisplayList* displayList = mDisplayList; - mDisplayList = nullptr; - mSkiaCanvasProxy.reset(nullptr); - return displayList; -} - -void DisplayListCanvas::callDrawGLFunction(Functor* functor, - GlFunctorLifecycleListener* listener) { - addDrawOp(new (alloc()) DrawFunctorOp(functor)); - mDisplayList->functors.push_back({functor, listener}); - mDisplayList->ref(listener); -} - -SkCanvas* DisplayListCanvas::asSkCanvas() { - LOG_ALWAYS_FATAL_IF(!mDisplayList, - "attempting to get an SkCanvas when we are not recording!"); - if (!mSkiaCanvasProxy) { - mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this)); - } - - // SkCanvas instances default to identity transform, but should inherit - // the state of this Canvas; if this code was in the SkiaCanvasProxy - // constructor, we couldn't cache mSkiaCanvasProxy. - SkMatrix parentTransform; - getMatrix(&parentTransform); - mSkiaCanvasProxy.get()->setMatrix(parentTransform); - - return mSkiaCanvasProxy.get(); -} - -int DisplayListCanvas::save(SaveFlags::Flags flags) { - addStateOp(new (alloc()) SaveOp((int) flags)); - return mState.save((int) flags); -} - -void DisplayListCanvas::restore() { - if (mRestoreSaveCount < 0) { - restoreToCount(getSaveCount() - 1); - return; - } - - mRestoreSaveCount--; - flushTranslate(); - mState.restore(); -} - -void DisplayListCanvas::restoreToCount(int saveCount) { - mRestoreSaveCount = saveCount; - flushTranslate(); - mState.restoreToCount(saveCount); -} - -int DisplayListCanvas::saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, SaveFlags::Flags flags) { - // force matrix/clip isolation for layer - flags |= SaveFlags::MatrixClip; - - paint = refPaint(paint); - addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, (int) flags)); - return mState.save((int) flags); -} - -void DisplayListCanvas::translate(float dx, float dy) { - if (dx == 0.0f && dy == 0.0f) return; - - mHasDeferredTranslate = true; - mTranslateX += dx; - mTranslateY += dy; - flushRestoreToCount(); - mState.translate(dx, dy, 0.0f); -} - -void DisplayListCanvas::rotate(float degrees) { - if (degrees == 0.0f) return; - - addStateOp(new (alloc()) RotateOp(degrees)); - mState.rotate(degrees); -} - -void DisplayListCanvas::scale(float sx, float sy) { - if (sx == 1.0f && sy == 1.0f) return; - - addStateOp(new (alloc()) ScaleOp(sx, sy)); - mState.scale(sx, sy); -} - -void DisplayListCanvas::skew(float sx, float sy) { - addStateOp(new (alloc()) SkewOp(sx, sy)); - mState.skew(sx, sy); -} - -void DisplayListCanvas::setMatrix(const SkMatrix& matrix) { - addStateOp(new (alloc()) SetMatrixOp(matrix)); - mState.setMatrix(matrix); -} - -void DisplayListCanvas::concat(const SkMatrix& matrix) { - addStateOp(new (alloc()) ConcatMatrixOp(matrix)); - mState.concatMatrix(matrix); -} - -bool DisplayListCanvas::getClipBounds(SkRect* outRect) const { - Rect bounds = mState.getLocalClipBounds(); - *outRect = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom); - return !(outRect->isEmpty()); -} - -bool DisplayListCanvas::quickRejectRect(float left, float top, float right, float bottom) const { - return mState.quickRejectConservative(left, top, right, bottom); -} - -bool DisplayListCanvas::quickRejectPath(const SkPath& path) const { - SkRect bounds = path.getBounds(); - return mState.quickRejectConservative(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); -} - - -bool DisplayListCanvas::clipRect(float left, float top, float right, float bottom, - SkRegion::Op op) { - addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op)); - return mState.clipRect(left, top, right, bottom, op); -} - -bool DisplayListCanvas::clipPath(const SkPath* path, SkRegion::Op op) { - path = refPath(path); - addStateOp(new (alloc()) ClipPathOp(path, op)); - return mState.clipPath(path, op); -} - -bool DisplayListCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) { - region = refRegion(region); - addStateOp(new (alloc()) ClipRegionOp(region, op)); - return mState.clipRegion(region, op); -} - -void DisplayListCanvas::drawRenderNode(RenderNode* renderNode) { - LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode"); - DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp( - renderNode, - *mState.currentTransform(), - mState.clipIsSimple()); - addRenderNodeOp(op); -} - -void DisplayListCanvas::drawLayer(DeferredLayerUpdater* layerHandle) { - // We ref the DeferredLayerUpdater due to its thread-safe ref-counting - // semantics. - mDisplayList->ref(layerHandle); - addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer())); -} - -void DisplayListCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { - bitmap = refBitmap(*bitmap); - paint = refPaint(paint); - - addDrawOp(new (alloc()) DrawBitmapOp(bitmap, paint)); -} - -void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, - const SkPaint* paint) { - save(SaveFlags::Matrix); - translate(left, top); - drawBitmap(&bitmap, paint); - restore(); -} - -void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, - const SkPaint* paint) { - if (matrix.isIdentity()) { - drawBitmap(&bitmap, paint); - } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) - && MathUtils::isPositive(matrix.getScaleX()) - && MathUtils::isPositive(matrix.getScaleY())) { - // SkMatrix::isScaleTranslate() not available in L - SkRect src; - SkRect dst; - bitmap.getBounds(&src); - matrix.mapRect(&dst, src); - drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, - dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint); - } else { - save(SaveFlags::Matrix); - concat(matrix); - drawBitmap(&bitmap, paint); - restore(); - } -} - -void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, - float srcRight, float srcBottom, float dstLeft, float dstTop, - float dstRight, float dstBottom, const SkPaint* paint) { - if (srcLeft == 0 && srcTop == 0 - && srcRight == bitmap.width() - && srcBottom == bitmap.height() - && (srcBottom - srcTop == dstBottom - dstTop) - && (srcRight - srcLeft == dstRight - dstLeft)) { - // transform simple rect to rect drawing case into position bitmap ops, since they merge - save(SaveFlags::Matrix); - translate(dstLeft, dstTop); - drawBitmap(&bitmap, paint); - restore(); - } else { - paint = refPaint(paint); - - if (paint && paint->getShader()) { - float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft); - float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop); - if (!MathUtils::areEqual(scaleX, 1.0f) || !MathUtils::areEqual(scaleY, 1.0f)) { - // Apply the scale transform on the canvas, so that the shader - // effectively calculates positions relative to src rect space - - save(SaveFlags::Matrix); - translate(dstLeft, dstTop); - scale(scaleX, scaleY); - - dstLeft = 0.0f; - dstTop = 0.0f; - dstRight = srcRight - srcLeft; - dstBottom = srcBottom - srcTop; - - addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap), - srcLeft, srcTop, srcRight, srcBottom, - dstLeft, dstTop, dstRight, dstBottom, paint)); - restore(); - return; - } - } - - addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap), - srcLeft, srcTop, srcRight, srcBottom, - dstLeft, dstTop, dstRight, dstBottom, paint)); - } -} - -void DisplayListCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint) { - int vertexCount = (meshWidth + 1) * (meshHeight + 1); - vertices = refBuffer<float>(vertices, vertexCount * 2); // 2 floats per vertex - paint = refPaint(paint); - colors = refBuffer<int>(colors, vertexCount); // 1 color per vertex - - addDrawOp(new (alloc()) DrawBitmapMeshOp(refBitmap(bitmap), meshWidth, meshHeight, - vertices, colors, paint)); -} - -void DisplayListCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& patch, - float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { - const SkBitmap* bitmapPtr = refBitmap(bitmap); - const Res_png_9patch* patchPtr = refPatch(&patch); - paint = refPaint(paint); - - addDrawOp(new (alloc()) DrawPatchOp(bitmapPtr, patchPtr, - dstLeft, dstTop, dstRight, dstBottom, paint)); -} - -void DisplayListCanvas::drawColor(int color, SkXfermode::Mode mode) { - addDrawOp(new (alloc()) DrawColorOp(color, mode)); -} - -void DisplayListCanvas::drawPaint(const SkPaint& paint) { - SkRect bounds; - if (getClipBounds(&bounds)) { - drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint); - } -} - - -void DisplayListCanvas::drawRect(float left, float top, float right, float bottom, - const SkPaint& paint) { - addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, refPaint(&paint))); -} - -void DisplayListCanvas::drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint& paint) { - addDrawOp(new (alloc()) DrawRoundRectOp(left, top, right, bottom, rx, ry, refPaint(&paint))); -} - -void DisplayListCanvas::drawRoundRect( - CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, - CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, - CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint) { - mDisplayList->ref(left); - mDisplayList->ref(top); - mDisplayList->ref(right); - mDisplayList->ref(bottom); - mDisplayList->ref(rx); - mDisplayList->ref(ry); - mDisplayList->ref(paint); - refBitmapsInShader(paint->value.getShader()); - addDrawOp(new (alloc()) DrawRoundRectPropsOp(&left->value, &top->value, - &right->value, &bottom->value, &rx->value, &ry->value, &paint->value)); -} - -void DisplayListCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { - addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, refPaint(&paint))); -} - -void DisplayListCanvas::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) { - mDisplayList->ref(x); - mDisplayList->ref(y); - mDisplayList->ref(radius); - mDisplayList->ref(paint); - refBitmapsInShader(paint->value.getShader()); - addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value, - &radius->value, &paint->value)); -} - -void DisplayListCanvas::drawOval(float left, float top, float right, float bottom, - const SkPaint& paint) { - addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, refPaint(&paint))); -} - -void DisplayListCanvas::drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) { - if (fabs(sweepAngle) >= 360.0f) { - drawOval(left, top, right, bottom, paint); - } else { - addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom, - startAngle, sweepAngle, useCenter, refPaint(&paint))); - } -} - -void DisplayListCanvas::drawPath(const SkPath& path, const SkPaint& paint) { - addDrawOp(new (alloc()) DrawPathOp(refPath(&path), refPaint(&paint))); -} - -void DisplayListCanvas::drawLines(const float* points, int count, const SkPaint& paint) { - points = refBuffer<float>(points, count); - - addDrawOp(new (alloc()) DrawLinesOp(points, count, refPaint(&paint))); -} - -void DisplayListCanvas::drawPoints(const float* points, int count, const SkPaint& paint) { - points = refBuffer<float>(points, count); - - addDrawOp(new (alloc()) DrawPointsOp(points, count, refPaint(&paint))); -} - -void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { - mDisplayList->ref(tree); - mDisplayList->vectorDrawables.push_back(tree); - addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds())); -} - -void DisplayListCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int count, - const SkPath& path, float hOffset, float vOffset, const SkPaint& paint) { - if (!glyphs || count <= 0) return; - - int bytesCount = 2 * count; - DrawOp* op = new (alloc()) DrawTextOnPathOp(refBuffer<glyph_t>(glyphs, count), - bytesCount, count, refPath(&path), - hOffset, vOffset, refPaint(&paint)); - addDrawOp(op); -} - -void DisplayListCanvas::drawGlyphs(const uint16_t* glyphs, const float* positions, - int count, const SkPaint& paint, float x, float y, - float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, - float totalAdvance) { - - if (!glyphs || count <= 0 || PaintUtils::paintWillNotDrawText(paint)) return; - - int bytesCount = count * 2; - positions = refBuffer<float>(positions, count * 2); - Rect bounds(boundsLeft, boundsTop, boundsRight, boundsBottom); - - DrawOp* op = new (alloc()) DrawTextOp(refBuffer<glyph_t>(glyphs, count), bytesCount, count, - x, y, positions, refPaint(&paint), totalAdvance, bounds); - addDrawOp(op); - drawTextDecorations(x, y, totalAdvance, paint); -} - -void DisplayListCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { - if (paint.getStyle() != SkPaint::kFill_Style || - (paint.isAntiAlias() && !mState.currentTransform()->isSimple())) { - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint); - it.next(); - } - } else { - int count = 0; - Vector<float> rects; - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - rects.push(r.fLeft); - rects.push(r.fTop); - rects.push(r.fRight); - rects.push(r.fBottom); - count += 4; - it.next(); - } - drawRects(rects.array(), count, &paint); - } -} - -void DisplayListCanvas::drawRects(const float* rects, int count, const SkPaint* paint) { - if (count <= 0) return; - - rects = refBuffer<float>(rects, count); - paint = refPaint(paint); - addDrawOp(new (alloc()) DrawRectsOp(rects, count, paint)); -} - -void DisplayListCanvas::setDrawFilter(SkDrawFilter* filter) { - mDrawFilter.reset(SkSafeRef(filter)); -} - -void DisplayListCanvas::insertReorderBarrier(bool enableReorder) { - flushRestoreToCount(); - flushTranslate(); - mDeferredBarrierType = enableReorder ? kBarrier_OutOfOrder : kBarrier_InOrder; -} - -void DisplayListCanvas::flushRestoreToCount() { - if (mRestoreSaveCount >= 0) { - addOpAndUpdateChunk(new (alloc()) RestoreToCountOp(mRestoreSaveCount)); - mRestoreSaveCount = -1; - } -} - -void DisplayListCanvas::flushTranslate() { - if (mHasDeferredTranslate) { - if (mTranslateX != 0.0f || mTranslateY != 0.0f) { - addOpAndUpdateChunk(new (alloc()) TranslateOp(mTranslateX, mTranslateY)); - mTranslateX = mTranslateY = 0.0f; - } - mHasDeferredTranslate = false; - } -} - -size_t DisplayListCanvas::addOpAndUpdateChunk(DisplayListOp* op) { - int insertIndex = mDisplayList->ops.size(); -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("unsupported"); -#else - mDisplayList->ops.push_back(op); -#endif - if (mDeferredBarrierType != kBarrier_None) { - // op is first in new chunk - mDisplayList->chunks.emplace_back(); - DisplayList::Chunk& newChunk = mDisplayList->chunks.back(); - newChunk.beginOpIndex = insertIndex; - newChunk.endOpIndex = insertIndex + 1; - newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder); - - int nextChildIndex = mDisplayList->children.size(); - newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex; - mDeferredBarrierType = kBarrier_None; - } else { - // standard case - append to existing chunk - mDisplayList->chunks.back().endOpIndex = insertIndex + 1; - } - return insertIndex; -} - -size_t DisplayListCanvas::flushAndAddOp(DisplayListOp* op) { - flushRestoreToCount(); - flushTranslate(); - return addOpAndUpdateChunk(op); -} - -size_t DisplayListCanvas::addStateOp(StateOp* op) { - return flushAndAddOp(op); -} - -size_t DisplayListCanvas::addDrawOp(DrawOp* op) { - Rect localBounds; - if (op->getLocalBounds(localBounds)) { - bool rejected = quickRejectRect(localBounds.left, localBounds.top, - localBounds.right, localBounds.bottom); - op->setQuickRejected(rejected); - } - - mDisplayList->hasDrawOps = true; - return flushAndAddOp(op); -} - -size_t DisplayListCanvas::addRenderNodeOp(DrawRenderNodeOp* op) { - int opIndex = addDrawOp(op); -#if !HWUI_NEW_OPS - int childIndex = mDisplayList->addChild(op); - - // update the chunk's child indices - DisplayList::Chunk& chunk = mDisplayList->chunks.back(); - chunk.endChildIndex = childIndex + 1; - - if (op->renderNode->stagingProperties().isProjectionReceiver()) { - // use staging property, since recording on UI thread - mDisplayList->projectionReceiveIndex = opIndex; - } -#endif - return opIndex; -} - -void DisplayListCanvas::refBitmapsInShader(const SkShader* shader) { - if (!shader) return; - - // If this paint has an SkShader that has an SkBitmap add - // it to the bitmap pile - SkBitmap bitmap; - SkShader::TileMode xy[2]; - if (shader->isABitmap(&bitmap, nullptr, xy)) { - refBitmap(bitmap); - return; - } - SkShader::ComposeRec rec; - if (shader->asACompose(&rec)) { - refBitmapsInShader(rec.fShaderA); - refBitmapsInShader(rec.fShaderB); - return; - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h deleted file mode 100644 index 664f79e283b6..000000000000 --- a/libs/hwui/DisplayListCanvas.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H -#define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H - -#include "CanvasState.h" -#include "DisplayList.h" -#include "RenderNode.h" -#include "ResourceCache.h" -#include "SkiaCanvasProxy.h" -#include "hwui/Canvas.h" -#include "utils/Macros.h" - -#include <SkDrawFilter.h> -#include <SkMatrix.h> -#include <SkPaint.h> -#include <SkPath.h> -#include <SkRegion.h> -#include <SkTLazy.h> -#include <cutils/compiler.h> - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -// Debug -#if DEBUG_DISPLAY_LIST - #define DISPLAY_LIST_LOGD(...) ALOGD(__VA_ARGS__) -#else - #define DISPLAY_LIST_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Display list -/////////////////////////////////////////////////////////////////////////////// - -class DeferredDisplayList; -class DeferredLayerUpdater; -class DisplayListOp; -class DrawOp; -class DrawRenderNodeOp; -class RenderNode; -class StateOp; - -/** - * Records drawing commands in a display list for later playback into an OpenGLRenderer. - */ -class ANDROID_API DisplayListCanvas: public Canvas, public CanvasStateClient { -public: - DisplayListCanvas(int width, int height); - virtual ~DisplayListCanvas(); - - virtual void resetRecording(int width, int height) override; - virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override; - -// ---------------------------------------------------------------------------- -// HWUI Canvas state operations -// ---------------------------------------------------------------------------- - - virtual void insertReorderBarrier(bool enableReorder) override; - -// ---------------------------------------------------------------------------- -// HWUI Canvas draw operations -// ---------------------------------------------------------------------------- - - // Shapes - virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, - CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, - CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint) override; - virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override; - -// ---------------------------------------------------------------------------- -// HWUI Canvas draw operations - special -// ---------------------------------------------------------------------------- - virtual void drawLayer(DeferredLayerUpdater* layerHandle) override; - virtual void drawRenderNode(RenderNode* renderNode) override; - virtual void callDrawGLFunction(Functor* functor, - GlFunctorLifecycleListener* listener) override; - -// ---------------------------------------------------------------------------- -// CanvasStateClient interface -// ---------------------------------------------------------------------------- - virtual void onViewportInitialized() override { } - virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override { } - virtual GLuint getTargetFbo() const override { return -1; } - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas interface -// ---------------------------------------------------------------------------- - virtual SkCanvas* asSkCanvas() override; - - virtual void setBitmap(const SkBitmap& bitmap) override { - LOG_ALWAYS_FATAL("DisplayListCanvas is not backed by a bitmap."); - } - - virtual bool isOpaque() override { return false; } - virtual int width() override { return mState.getWidth(); } - virtual int height() override { return mState.getHeight(); } - - virtual void setHighContrastText(bool highContrastText) override { - mHighContrastText = highContrastText; - } - virtual bool isHighContrastText() override { return mHighContrastText; } - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas state operations -// ---------------------------------------------------------------------------- - // Save (layer) - virtual int getSaveCount() const override { return mState.getSaveCount(); } - virtual int save(SaveFlags::Flags flags) override; - virtual void restore() override; - virtual void restoreToCount(int saveCount) override; - - virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint, - SaveFlags::Flags flags) override; - virtual int saveLayerAlpha(float left, float top, float right, float bottom, - int alpha, SaveFlags::Flags flags) override { - SkPaint paint; - paint.setAlpha(alpha); - return saveLayer(left, top, right, bottom, &paint, flags); - } - - // Matrix - virtual void getMatrix(SkMatrix* outMatrix) const override { mState.getMatrix(outMatrix); } - virtual void setMatrix(const SkMatrix& matrix) override; - - virtual void concat(const SkMatrix& matrix) override; - virtual void rotate(float degrees) override; - virtual void scale(float sx, float sy) override; - virtual void skew(float sx, float sy) override; - virtual void translate(float dx, float dy) override; - - // Clip - virtual bool getClipBounds(SkRect* outRect) const override; - virtual bool quickRejectRect(float left, float top, float right, float bottom) const override; - virtual bool quickRejectPath(const SkPath& path) const override; - - virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) override; - virtual bool clipPath(const SkPath* path, SkRegion::Op op) override; - virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override; - - // Misc - virtual SkDrawFilter* getDrawFilter() override { return mDrawFilter.get(); } - virtual void setDrawFilter(SkDrawFilter* filter) override; - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas draw operations -// ---------------------------------------------------------------------------- - virtual void drawColor(int color, SkXfermode::Mode mode) override; - virtual void drawPaint(const SkPaint& paint) override; - - // Geometry - virtual void drawPoint(float x, float y, const SkPaint& paint) override { - float points[2] = { x, y }; - drawPoints(points, 2, paint); - } - virtual void drawPoints(const float* points, int count, const SkPaint& paint) override; - virtual void drawLine(float startX, float startY, float stopX, float stopY, - const SkPaint& paint) override { - float points[4] = { startX, startY, stopX, stopY }; - drawLines(points, 4, paint); - } - virtual void drawLines(const float* points, int count, const SkPaint& paint) override; - virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override; - virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override; - virtual void drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint& paint) override; - virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override; - virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint) override; - virtual void drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override; - virtual void drawPath(const SkPath& path, const SkPaint& paint) override; - virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, - const float* verts, const float* tex, const int* colors, - const uint16_t* indices, int indexCount, const SkPaint& paint) override - { /* DisplayListCanvas does not support drawVertices(); ignore */ } - - // Bitmap-based - virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) override; - virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, - const SkPaint* paint) override; - virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, - float srcRight, float srcBottom, float dstLeft, float dstTop, - float dstRight, float dstBottom, const SkPaint* paint) override; - virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint) override; - virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk, - float dstLeft, float dstTop, float dstRight, float dstBottom, - const SkPaint* paint) override; - - virtual void drawVectorDrawable(VectorDrawableRoot* tree) override; - - // Text - virtual void drawGlyphs(const uint16_t* glyphs, const float* positions, int count, - const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop, - float boundsRight, float boundsBottom, float totalAdvance) override; - virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path, - float hOffset, float vOffset, const SkPaint& paint) override; - virtual bool drawTextAbsolutePos() const override { return false; } - -private: - - CanvasState mState; - std::unique_ptr<SkiaCanvasProxy> mSkiaCanvasProxy; - - enum DeferredBarrierType { - kBarrier_None, - kBarrier_InOrder, - kBarrier_OutOfOrder, - }; - - void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint); - void drawRects(const float* rects, int count, const SkPaint* paint); - - void flushRestoreToCount(); - void flushTranslate(); - void flushReorderBarrier(); - - LinearAllocator& alloc() { return mDisplayList->allocator; } - - // Each method returns final index of op - size_t addOpAndUpdateChunk(DisplayListOp* op); - // flushes any deferred operations, and appends the op - size_t flushAndAddOp(DisplayListOp* op); - - size_t addStateOp(StateOp* op); - size_t addDrawOp(DrawOp* op); - size_t addRenderNodeOp(DrawRenderNodeOp* op); - - void refBitmapsInShader(const SkShader* shader); - - template<class T> - inline const T* refBuffer(const T* srcBuffer, int32_t count) { - if (!srcBuffer) return nullptr; - - T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T)); - memcpy(dstBuffer, srcBuffer, count * sizeof(T)); - return dstBuffer; - } - - inline const SkPath* refPath(const SkPath* path) { - if (!path) return nullptr; - - // The points/verbs within the path are refcounted so this copy operation - // is inexpensive and maintains the generationID of the original path. - const SkPath* cachedPath = new SkPath(*path); - mDisplayList->pathResources.push_back(cachedPath); - return cachedPath; - } - - inline const SkPaint* refPaint(const SkPaint* paint) { - if (!paint) return nullptr; - - // If there is a draw filter apply it here and store the modified paint - // so that we don't need to modify the paint every time we access it. - SkTLazy<SkPaint> filteredPaint; - if (mDrawFilter.get()) { - filteredPaint.set(*paint); - mDrawFilter->filter(filteredPaint.get(), SkDrawFilter::kPaint_Type); - paint = filteredPaint.get(); - } - - // compute the hash key for the paint and check the cache. - const uint32_t key = paint->getHash(); - const SkPaint* cachedPaint = mPaintMap.valueFor(key); - // In the unlikely event that 2 unique paints have the same hash we do a - // object equality check to ensure we don't erroneously dedup them. - if (cachedPaint == nullptr || *cachedPaint != *paint) { - cachedPaint = new SkPaint(*paint); - std::unique_ptr<const SkPaint> copy(cachedPaint); - mDisplayList->paints.push_back(std::move(copy)); - - // replaceValueFor() performs an add if the entry doesn't exist - mPaintMap.replaceValueFor(key, cachedPaint); - refBitmapsInShader(cachedPaint->getShader()); - } - - return cachedPaint; - } - - inline const SkRegion* refRegion(const SkRegion* region) { - if (!region) { - return region; - } - - const SkRegion* cachedRegion = mRegionMap.valueFor(region); - // TODO: Add generation ID to SkRegion - if (cachedRegion == nullptr) { - std::unique_ptr<const SkRegion> copy(new SkRegion(*region)); - cachedRegion = copy.get(); - mDisplayList->regions.push_back(std::move(copy)); - - // replaceValueFor() performs an add if the entry doesn't exist - mRegionMap.replaceValueFor(region, cachedRegion); - } - - return cachedRegion; - } - - inline const SkBitmap* refBitmap(const SkBitmap& bitmap) { - // Note that this assumes the bitmap is immutable. There are cases this won't handle - // correctly, such as creating the bitmap from scratch, drawing with it, changing its - // contents, and drawing again. The only fix would be to always copy it the first time, - // which doesn't seem worth the extra cycles for this unlikely case. - SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap); - mDisplayList->bitmapResources.push_back(localBitmap); - return localBitmap; - } - - inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) { - mDisplayList->patchResources.push_back(patch); - mResourceCache.incrementRefcount(patch); - return patch; - } - - DefaultKeyedVector<uint32_t, const SkPaint*> mPaintMap; - DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap; - DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap; - - ResourceCache& mResourceCache; - DisplayList* mDisplayList; - - float mTranslateX; - float mTranslateY; - bool mHasDeferredTranslate; - DeferredBarrierType mDeferredBarrierType; - bool mHighContrastText; - - int mRestoreSaveCount; - - SkAutoTUnref<SkDrawFilter> mDrawFilter; - - friend class RenderNode; - -}; // class DisplayListCanvas - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_DISPLAY_LIST_RENDERER_H diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h deleted file mode 100644 index 2a859132e783..000000000000 --- a/libs/hwui/DisplayListOp.h +++ /dev/null @@ -1,1555 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_DISPLAY_OPERATION_H -#define ANDROID_HWUI_DISPLAY_OPERATION_H - -#include "OpenGLRenderer.h" -#include "AssetAtlas.h" -#include "DeferredDisplayList.h" -#include "DisplayListCanvas.h" -#include "GammaFontRenderer.h" -#include "Patch.h" -#include "RenderNode.h" -#include "renderstate/RenderState.h" -#include "UvMapper.h" -#include "utils/LinearAllocator.h" -#include "utils/PaintUtils.h" -#include "VectorDrawable.h" - -#include <algorithm> - -#include <SkColor.h> -#include <SkPath.h> -#include <SkPathOps.h> -#include <SkXfermode.h> - -#include <private/hwui/DrawGlInfo.h> - -// Use OP_LOG for logging with arglist, OP_LOGS if just printing char* -#define OP_LOGS(s) OP_LOG("%s", (s)) -#define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ ) - -namespace android { -namespace uirenderer { - -/** - * Structure for storing canvas operations when they are recorded into a DisplayList, so that they - * may be replayed to an OpenGLRenderer. - * - * To avoid individual memory allocations, DisplayListOps may only be allocated into a - * LinearAllocator's managed memory buffers. Each pointer held by a DisplayListOp is either a - * pointer into memory also allocated in the LinearAllocator (mostly for text and float buffers) or - * references a externally refcounted object (Sk... and Skia... objects). ~DisplayListOp() is - * never called as LinearAllocators are simply discarded, so no memory management should be done in - * this class. - */ -class DisplayListOp { -public: - // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted. - // standard new() intentionally not implemented, and delete/deconstructor should never be used. - virtual ~DisplayListOp() { LOG_ALWAYS_FATAL("Destructor not supported"); } - static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); } - static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/ - static void* operator new(size_t size, LinearAllocator& allocator) { - // FIXME: Quick hack to keep old pipeline working, delete this when - // we no longer need to support HWUI_NEWOPS := false - return allocator.alloc<char>(size); - } - - enum OpLogFlag { - kOpLogFlag_Recurse = 0x1, - kOpLogFlag_JSON = 0x2 // TODO: add? - }; - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) = 0; - - virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, - bool useQuickReject) = 0; - - virtual void output(int level, uint32_t logFlags = 0) const = 0; - - // NOTE: it would be nice to declare constants and overriding the implementation in each op to - // point at the constants, but that seems to require a .cpp file - virtual const char* name() = 0; -}; - -class StateOp : public DisplayListOp { -public: - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - // default behavior only affects immediate, deferrable state, issue directly to renderer - applyState(deferStruct.mRenderer, saveCount); - } - - /** - * State operations are applied directly to the renderer, but can cause the deferred drawing op - * list to flush - */ - virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, - bool useQuickReject) override { - applyState(replayStruct.mRenderer, saveCount); - } - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const = 0; -}; - -class DrawOp : public DisplayListOp { -friend class MergingDrawBatch; -public: - DrawOp(const SkPaint* paint) - : mPaint(paint), mQuickRejected(false) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - if (mQuickRejected && CC_LIKELY(useQuickReject)) { - return; - } - - deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this); - } - - virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, - bool useQuickReject) override { - if (mQuickRejected && CC_LIKELY(useQuickReject)) { - return; - } - - applyDraw(replayStruct.mRenderer, replayStruct.mDirty); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0; - - /** - * Draw multiple instances of an operation, must be overidden for operations that merge - * - * Currently guarantees certain similarities between ops (see MergingDrawBatch::canMergeWith), - * and pure translation transformations. Other guarantees of similarity should be enforced by - * reducing which operations are tagged as mergeable. - */ - virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const std::vector<OpStatePair>& ops, const Rect& bounds) { - for (unsigned int i = 0; i < ops.size(); i++) { - renderer.restoreDisplayState(*(ops[i].state), true); - ops[i].op->applyDraw(renderer, dirty); - } - } - - /** - * When this method is invoked the state field is initialized to have the - * final rendering state. We can thus use it to process data as it will be - * used at draw time. - * - * Additionally, this method allows subclasses to provide defer-time preferences for batching - * and merging. - * - * if a subclass can set deferInfo.mergeable to true, it should implement multiDraw() - */ - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) {} - - /** - * Query the conservative, local bounds (unmapped) bounds of the op. - * - * returns true if bounds exist - */ - virtual bool getLocalBounds(Rect& localBounds) { - return false; - } - - // TODO: better refine localbounds usage - void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; } - bool getQuickRejected() { return mQuickRejected; } - - virtual bool hasTextShadow() const { - return false; - } - - inline float strokeWidthOutset() { - // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced - // 1.0 stroke, treat 1.0 as minimum. - - // TODO: it would be nice if this could take scale into account, but scale isn't stable - // since higher levels of the view hierarchy can change scale out from underneath it. - return std::max(mPaint->getStrokeWidth(), 1.0f) * 0.5f; - } - -protected: - // Helper method for determining op opaqueness. Assumes op fills its bounds in local - // coordinates, and that paint's alpha is used - inline bool isOpaqueOverBounds(const DeferredDisplayState& state) { - // ensure that local bounds cover mapped bounds - if (!state.mMatrix.isSimple()) return false; - - if (state.mRoundRectClipState) return false; - - // check state/paint for transparency - if (mPaint) { - if (mPaint->getAlpha() != 0xFF) { - return false; - } - if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) { - return false; - } - if (PaintUtils::isBlendedColorFilter(mPaint->getColorFilter())) { - return false; - } - } - - if (state.mAlpha != 1.0f) return false; - - SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint); - return (mode == SkXfermode::kSrcOver_Mode || - mode == SkXfermode::kSrc_Mode); - - } - - const SkPaint* mPaint; - bool mQuickRejected; -}; - -class DrawBoundedOp : public DrawOp { -public: - DrawBoundedOp(float left, float top, float right, float bottom, const SkPaint* paint) - : DrawOp(paint), mLocalBounds(left, top, right, bottom) {} - - DrawBoundedOp(const Rect& localBounds, const SkPaint* paint) - : DrawOp(paint), mLocalBounds(localBounds) {} - - // Calculates bounds as smallest rect encompassing all points - // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in - // subclass' constructor) - DrawBoundedOp(const float* points, int count, const SkPaint* paint) - : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) { - for (int i = 2; i < count; i += 2) { - mLocalBounds.left = std::min(mLocalBounds.left, points[i]); - mLocalBounds.right = std::max(mLocalBounds.right, points[i]); - mLocalBounds.top = std::min(mLocalBounds.top, points[i + 1]); - mLocalBounds.bottom = std::max(mLocalBounds.bottom, points[i + 1]); - } - } - - // default empty constructor for bounds, to be overridden in child constructor body - DrawBoundedOp(const SkPaint* paint): DrawOp(paint) { } - - virtual bool getLocalBounds(Rect& localBounds) override { - localBounds.set(mLocalBounds); - PaintUtils::TextShadow textShadow; - if (PaintUtils::getTextShadow(mPaint, &textShadow)) { - Rect shadow(mLocalBounds); - shadow.translate(textShadow.dx, textShadow.dx); - shadow.outset(textShadow.radius); - localBounds.unionWith(shadow); - } - return true; - } - -protected: - Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint -}; - -/////////////////////////////////////////////////////////////////////////////// -// STATE OPERATIONS - these may affect the state of the canvas/renderer, but do -// not directly draw or alter output -/////////////////////////////////////////////////////////////////////////////// - -class SaveOp : public StateOp { -public: - SaveOp(int flags) - : mFlags(flags) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - int newSaveCount = deferStruct.mRenderer.save(mFlags); - deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount); - } - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.save(mFlags); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Save flags %x", mFlags); - } - - virtual const char* name() override { return "Save"; } - - int getFlags() const { return mFlags; } -private: - int mFlags; -}; - -class RestoreToCountOp : public StateOp { -public: - RestoreToCountOp(int count) - : mCount(count) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer, - this, saveCount + mCount); - deferStruct.mRenderer.restoreToCount(saveCount + mCount); - } - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.restoreToCount(saveCount + mCount); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Restore to count %d", mCount); - } - - virtual const char* name() override { return "RestoreToCount"; } - -private: - int mCount; -}; - -class SaveLayerOp : public StateOp { -public: - SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags) - : mArea(left, top, right, bottom) - , mPaint(&mCachedPaint) - , mFlags(flags) - , mConvexMask(nullptr) { - mCachedPaint.setAlpha(alpha); - } - - SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags) - : mArea(left, top, right, bottom) - , mPaint(paint) - , mFlags(flags) - , mConvexMask(nullptr) - {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - // NOTE: don't bother with actual saveLayer, instead issuing it at flush time - int newSaveCount = deferStruct.mRenderer.getSaveCount(); - deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount); - - // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just - // setup the snapshot for deferral, and re-issue the op at flush time - deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom, - mPaint, mFlags); - } - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, - mPaint, mFlags, mConvexMask); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("SaveLayer%s of area " RECT_STRING, - (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea)); - } - - virtual const char* name() override { - return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; - } - - int getFlags() { return mFlags; } - - // Called to make SaveLayerOp clip to the provided mask when drawing back/restored - void setMask(const SkPath* convexMask) { - mConvexMask = convexMask; - } - -private: - bool isSaveLayerAlpha() const { - SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint); - int alpha = PaintUtils::getAlphaDirect(mPaint); - return alpha < 255 && mode == SkXfermode::kSrcOver_Mode; - } - - Rect mArea; - const SkPaint* mPaint; - SkPaint mCachedPaint; - int mFlags; - - // Convex path, points at data in RenderNode, valid for the duration of the frame only - // Only used for masking the SaveLayer which wraps projected RenderNodes - const SkPath* mConvexMask; -}; - -class TranslateOp : public StateOp { -public: - TranslateOp(float dx, float dy) - : mDx(dx), mDy(dy) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.translate(mDx, mDy); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Translate by %f %f", mDx, mDy); - } - - virtual const char* name() override { return "Translate"; } - -private: - float mDx; - float mDy; -}; - -class RotateOp : public StateOp { -public: - RotateOp(float degrees) - : mDegrees(degrees) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.rotate(mDegrees); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Rotate by %f degrees", mDegrees); - } - - virtual const char* name() override { return "Rotate"; } - -private: - float mDegrees; -}; - -class ScaleOp : public StateOp { -public: - ScaleOp(float sx, float sy) - : mSx(sx), mSy(sy) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.scale(mSx, mSy); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Scale by %f %f", mSx, mSy); - } - - virtual const char* name() override { return "Scale"; } - -private: - float mSx; - float mSy; -}; - -class SkewOp : public StateOp { -public: - SkewOp(float sx, float sy) - : mSx(sx), mSy(sy) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.skew(mSx, mSy); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Skew by %f %f", mSx, mSy); - } - - virtual const char* name() override { return "Skew"; } - -private: - float mSx; - float mSy; -}; - -class SetMatrixOp : public StateOp { -public: - SetMatrixOp(const SkMatrix& matrix) - : mMatrix(matrix) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - // Setting a matrix on a Canvas isn't equivalent to setting a total matrix on the scene. - // Set a canvas-relative matrix on the renderer instead. - renderer.setLocalMatrix(mMatrix); - } - - virtual void output(int level, uint32_t logFlags) const override { - if (mMatrix.isIdentity()) { - OP_LOGS("SetMatrix (reset)"); - } else { - OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix)); - } - } - - virtual const char* name() override { return "SetMatrix"; } - -private: - const SkMatrix mMatrix; -}; - -class ConcatMatrixOp : public StateOp { -public: - ConcatMatrixOp(const SkMatrix& matrix) - : mMatrix(matrix) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.concatMatrix(mMatrix); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix)); - } - - virtual const char* name() override { return "ConcatMatrix"; } - -private: - const SkMatrix mMatrix; -}; - -class ClipOp : public StateOp { -public: - ClipOp(SkRegion::Op op) : mOp(op) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - // NOTE: must defer op BEFORE applying state, since it may read clip - deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this); - - // TODO: Can we avoid applying complex clips at defer time? - applyState(deferStruct.mRenderer, saveCount); - } - - bool canCauseComplexClip() { - return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect(); - } - -protected: - virtual bool isRect() { return false; } - - SkRegion::Op mOp; -}; - -class ClipRectOp : public ClipOp { -public: - ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op) - : ClipOp(op), mArea(left, top, right, bottom) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea)); - } - - virtual const char* name() override { return "ClipRect"; } - -protected: - virtual bool isRect() override { return true; } - -private: - Rect mArea; -}; - -class ClipPathOp : public ClipOp { -public: - ClipPathOp(const SkPath* path, SkRegion::Op op) - : ClipOp(op), mPath(path) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.clipPath(mPath, mOp); - } - - virtual void output(int level, uint32_t logFlags) const override { - SkRect bounds = mPath->getBounds(); - OP_LOG("ClipPath bounds " RECT_STRING, - bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); - } - - virtual const char* name() override { return "ClipPath"; } - -private: - const SkPath* mPath; -}; - -class ClipRegionOp : public ClipOp { -public: - ClipRegionOp(const SkRegion* region, SkRegion::Op op) - : ClipOp(op), mRegion(region) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.clipRegion(mRegion, mOp); - } - - virtual void output(int level, uint32_t logFlags) const override { - SkIRect bounds = mRegion->getBounds(); - OP_LOG("ClipRegion bounds %d %d %d %d", - bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); - } - - virtual const char* name() override { return "ClipRegion"; } - -private: - const SkRegion* mRegion; -}; - -/////////////////////////////////////////////////////////////////////////////// -// DRAW OPERATIONS - these are operations that can draw to the canvas's device -/////////////////////////////////////////////////////////////////////////////// - -class DrawBitmapOp : public DrawBoundedOp { -public: - DrawBitmapOp(const SkBitmap* bitmap, const SkPaint* paint) - : DrawBoundedOp(0, 0, bitmap->width(), bitmap->height(), paint) - , mBitmap(bitmap) - , mEntryValid(false), mEntry(nullptr) { - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawBitmap(mBitmap, mPaint); - } - - AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) { - if (!mEntryValid) { - mEntryValid = true; - mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap->pixelRef()); - } - return mEntry; - } - -#define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \ - TextureVertex::set((ptr)++, (posRect).xDim - (offsetRect).left, (posRect).yDim - (offsetRect).top, \ - (texCoordsRect).xDim, (texCoordsRect).yDim) - - /** - * This multi-draw operation builds a mesh on the stack by generating a quad - * for each bitmap in the batch. This method is also responsible for dirtying - * the current layer, if any. - */ - virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const std::vector<OpStatePair>& ops, const Rect& bounds) override { - const DeferredDisplayState& firstState = *(ops[0].state); - renderer.restoreDisplayState(firstState, true); // restore all but the clip - - TextureVertex vertices[6 * ops.size()]; - TextureVertex* vertex = &vertices[0]; - - const bool hasLayer = renderer.hasLayer(); - bool pureTranslate = true; - - // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op, - // and allowing them to be merged in getBatchId() - for (unsigned int i = 0; i < ops.size(); i++) { - const DeferredDisplayState& state = *(ops[i].state); - const Rect& opBounds = state.mBounds; - // When we reach multiDraw(), the matrix can be either - // pureTranslate or simple (translate and/or scale). - // If the matrix is not pureTranslate, then we have a scale - pureTranslate &= state.mMatrix.isPureTranslate(); - - Rect texCoords(0, 0, 1, 1); - ((DrawBitmapOp*) ops[i].op)->uvMap(renderer, texCoords); - - SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top); - SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top); - SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom); - - SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom); - SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top); - SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom); - - if (hasLayer) { - renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom); - } - } - - renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0], - pureTranslate, bounds, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw bitmap %p of size %dx%d%s", - mBitmap, mBitmap->width(), mBitmap->height(), - mEntry ? " using AssetAtlas" : ""); - } - - virtual const char* name() override { return "DrawBitmap"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; - deferInfo.mergeId = getAtlasEntry(renderer) ? - (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap; - - // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation - // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in - // MergingDrawBatch::canMergeWith() - // TODO: support clipped bitmaps by handling them in SET_TEXTURE - deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() && - !state.mClipSideFlags && - PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode && - (mBitmap->colorType() != kAlpha_8_SkColorType); - } - - void uvMap(OpenGLRenderer& renderer, Rect& texCoords) { - if (getAtlasEntry(renderer)) { - mEntry->uvMapper.map(texCoords); - } - } - - const SkBitmap* bitmap() { return mBitmap; } -protected: - const SkBitmap* mBitmap; - bool mEntryValid; - AssetAtlas::Entry* mEntry; -}; - -class DrawBitmapRectOp : public DrawBoundedOp { -public: - DrawBitmapRectOp(const SkBitmap* bitmap, - float srcLeft, float srcTop, float srcRight, float srcBottom, - float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) - : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint), - mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawBitmap(mBitmap, mSrc, mLocalBounds, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw bitmap %p src=" RECT_STRING ", dst=" RECT_STRING, - mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds)); - } - - virtual const char* name() override { return "DrawBitmapRect"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; - } - -private: - const SkBitmap* mBitmap; - Rect mSrc; -}; - -class DrawBitmapMeshOp : public DrawBoundedOp { -public: - DrawBitmapMeshOp(const SkBitmap* bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint) - : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint), - mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight), - mVertices(vertices), mColors(colors) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight, - mVertices, mColors, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight); - } - - virtual const char* name() override { return "DrawBitmapMesh"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; - } - -private: - const SkBitmap* mBitmap; - int mMeshWidth; - int mMeshHeight; - const float* mVertices; - const int* mColors; -}; - -class DrawPatchOp : public DrawBoundedOp { -public: - DrawPatchOp(const SkBitmap* bitmap, const Res_png_9patch* patch, - float left, float top, float right, float bottom, const SkPaint* paint) - : DrawBoundedOp(left, top, right, bottom, paint), - mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(nullptr), - mEntryValid(false), mEntry(nullptr) { - }; - - AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) { - if (!mEntryValid) { - mEntryValid = true; - mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap->pixelRef()); - } - return mEntry; - } - - const Patch* getMesh(OpenGLRenderer& renderer) { - if (!mMesh || renderer.getCaches().patchCache.getGenerationId() != mGenerationId) { - PatchCache& cache = renderer.getCaches().patchCache; - mMesh = cache.get(getAtlasEntry(renderer), mBitmap->width(), mBitmap->height(), - mLocalBounds.getWidth(), mLocalBounds.getHeight(), mPatch); - mGenerationId = cache.getGenerationId(); - } - return mMesh; - } - - /** - * This multi-draw operation builds an indexed mesh on the stack by copying - * and transforming the vertices of each 9-patch in the batch. This method - * is also responsible for dirtying the current layer, if any. - */ - virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const std::vector<OpStatePair>& ops, const Rect& bounds) override { - const DeferredDisplayState& firstState = *(ops[0].state); - renderer.restoreDisplayState(firstState, true); // restore all but the clip - - // Batches will usually contain a small number of items so it's - // worth performing a first iteration to count the exact number - // of vertices we need in the new mesh - uint32_t totalVertices = 0; - for (unsigned int i = 0; i < ops.size(); i++) { - totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount; - } - - const bool hasLayer = renderer.hasLayer(); - - uint32_t indexCount = 0; - - TextureVertex vertices[totalVertices]; - TextureVertex* vertex = &vertices[0]; - - // Create a mesh that contains the transformed vertices for all the - // 9-patch objects that are part of the batch. Note that onDefer() - // enforces ops drawn by this function to have a pure translate or - // identity matrix - for (unsigned int i = 0; i < ops.size(); i++) { - DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op; - const DeferredDisplayState* state = ops[i].state; - const Patch* opMesh = patchOp->getMesh(renderer); - uint32_t vertexCount = opMesh->verticesCount; - if (vertexCount == 0) continue; - - // We use the bounds to know where to translate our vertices - // Using patchOp->state.mBounds wouldn't work because these - // bounds are clipped - const float tx = (int) floorf(state->mMatrix.getTranslateX() + - patchOp->mLocalBounds.left + 0.5f); - const float ty = (int) floorf(state->mMatrix.getTranslateY() + - patchOp->mLocalBounds.top + 0.5f); - - // Copy & transform all the vertices for the current operation - TextureVertex* opVertices = opMesh->vertices.get(); - for (uint32_t j = 0; j < vertexCount; j++, opVertices++) { - TextureVertex::set(vertex++, - opVertices->x + tx, opVertices->y + ty, - opVertices->u, opVertices->v); - } - - // Dirty the current layer if possible. When the 9-patch does not - // contain empty quads we can take a shortcut and simply set the - // dirty rect to the object's bounds. - if (hasLayer) { - if (!opMesh->hasEmptyQuads) { - renderer.dirtyLayer(tx, ty, - tx + patchOp->mLocalBounds.getWidth(), - ty + patchOp->mLocalBounds.getHeight()); - } else { - const size_t count = opMesh->quads.size(); - for (size_t i = 0; i < count; i++) { - const Rect& quadBounds = opMesh->quads[i]; - const float x = tx + quadBounds.left; - const float y = ty + quadBounds.top; - renderer.dirtyLayer(x, y, - x + quadBounds.getWidth(), y + quadBounds.getHeight()); - } - } - } - - indexCount += opMesh->indexCount; - } - - renderer.drawPatches(mBitmap, getAtlasEntry(renderer), - &vertices[0], indexCount, mPaint); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - // We're not calling the public variant of drawPatch() here - // This method won't perform the quickReject() since we've already done it at this point - renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(renderer), - mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom, - mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw patch " RECT_STRING "%s", RECT_ARGS(mLocalBounds), - mEntry ? " with AssetAtlas" : ""); - } - - virtual const char* name() override { return "DrawPatch"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch; - deferInfo.mergeId = getAtlasEntry(renderer) ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap; - deferInfo.mergeable = state.mMatrix.isPureTranslate() && - PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; - deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque(); - } - -private: - const SkBitmap* mBitmap; - const Res_png_9patch* mPatch; - - uint32_t mGenerationId; - const Patch* mMesh; - - bool mEntryValid; - AssetAtlas::Entry* mEntry; -}; - -class DrawColorOp : public DrawOp { -public: - DrawColorOp(int color, SkXfermode::Mode mode) - : DrawOp(nullptr), mColor(color), mMode(mode) {}; - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawColor(mColor, mMode); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw color %#x, mode %d", mColor, mMode); - } - - virtual const char* name() override { return "DrawColor"; } - -private: - int mColor; - SkXfermode::Mode mMode; -}; - -class DrawStrokableOp : public DrawBoundedOp { -public: - DrawStrokableOp(float left, float top, float right, float bottom, const SkPaint* paint) - : DrawBoundedOp(left, top, right, bottom, paint) {}; - DrawStrokableOp(const Rect& localBounds, const SkPaint* paint) - : DrawBoundedOp(localBounds, paint) {}; - - virtual bool getLocalBounds(Rect& localBounds) override { - localBounds.set(mLocalBounds); - if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) { - localBounds.outset(strokeWidthOutset()); - } - return true; - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - if (mPaint->getPathEffect()) { - deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture; - } else { - deferInfo.batchId = mPaint->isAntiAlias() ? - DeferredDisplayList::kOpBatch_AlphaVertices : - DeferredDisplayList::kOpBatch_Vertices; - } - } -}; - -class DrawRectOp : public DrawStrokableOp { -public: - DrawRectOp(float left, float top, float right, float bottom, const SkPaint* paint) - : DrawStrokableOp(left, top, right, bottom, paint) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawRect(mLocalBounds.left, mLocalBounds.top, - mLocalBounds.right, mLocalBounds.bottom, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Rect " RECT_STRING, RECT_ARGS(mLocalBounds)); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - DrawStrokableOp::onDefer(renderer, deferInfo, state); - deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && - mPaint->getStyle() == SkPaint::kFill_Style; - } - - virtual const char* name() override { return "DrawRect"; } -}; - -class DrawRectsOp : public DrawBoundedOp { -public: - DrawRectsOp(const float* rects, int count, const SkPaint* paint) - : DrawBoundedOp(rects, count, paint), - mRects(rects), mCount(count) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawRects(mRects, mCount, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Rects count %d", mCount); - } - - virtual const char* name() override { return "DrawRects"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices; - } - -private: - const float* mRects; - int mCount; -}; - -class DrawRoundRectOp : public DrawStrokableOp { -public: - DrawRoundRectOp(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint* paint) - : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top, - mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw RoundRect " RECT_STRING ", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - DrawStrokableOp::onDefer(renderer, deferInfo, state); - if (!mPaint->getPathEffect()) { - renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, *mPaint, - mLocalBounds.getWidth(), mLocalBounds.getHeight(), mRx, mRy); - } - } - - virtual const char* name() override { return "DrawRoundRect"; } - -private: - float mRx; - float mRy; -}; - -class DrawRoundRectPropsOp : public DrawOp { -public: - DrawRoundRectPropsOp(float* left, float* top, float* right, float* bottom, - float *rx, float *ry, const SkPaint* paint) - : DrawOp(paint), mLeft(left), mTop(top), mRight(right), mBottom(bottom), - mRx(rx), mRy(ry) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom, - *mRx, *mRy, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw RoundRect Props " RECT_STRING ", rx %f, ry %f", - *mLeft, *mTop, *mRight, *mBottom, *mRx, *mRy); - } - - virtual const char* name() override { return "DrawRoundRectProps"; } - -private: - float* mLeft; - float* mTop; - float* mRight; - float* mBottom; - float* mRx; - float* mRy; -}; - -class DrawCircleOp : public DrawStrokableOp { -public: - DrawCircleOp(float x, float y, float radius, const SkPaint* paint) - : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint), - mX(x), mY(y), mRadius(radius) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawCircle(mX, mY, mRadius, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius); - } - - virtual const char* name() override { return "DrawCircle"; } - -private: - float mX; - float mY; - float mRadius; -}; - -class DrawCirclePropsOp : public DrawOp { -public: - DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint) - : DrawOp(paint), mX(x), mY(y), mRadius(radius) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawCircle(*mX, *mY, *mRadius, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Circle Props x %p, y %p, r %p", mX, mY, mRadius); - } - - virtual const char* name() override { return "DrawCircleProps"; } - -private: - float* mX; - float* mY; - float* mRadius; -}; - -class DrawVectorDrawableOp : public DrawOp { -public: - DrawVectorDrawableOp(VectorDrawableRoot* tree, const SkRect& bounds) - : DrawOp(nullptr), mTree(tree), mDst(bounds) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - const SkBitmap& bitmap = mTree->getBitmapUpdateIfDirty(); - SkPaint* paint = mTree->getPaint(); - renderer.drawBitmap(&bitmap, Rect(0, 0, bitmap.width(), bitmap.height()), - mDst, paint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Vector Drawable %p", mTree); - } - - virtual const char* name() override { return "DrawVectorDrawable"; } - -private: - VectorDrawableRoot* mTree; - SkRect mDst; - -}; - -class DrawOvalOp : public DrawStrokableOp { -public: - DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint) - : DrawStrokableOp(left, top, right, bottom, paint) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawOval(mLocalBounds.left, mLocalBounds.top, - mLocalBounds.right, mLocalBounds.bottom, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Oval " RECT_STRING, RECT_ARGS(mLocalBounds)); - } - - virtual const char* name() override { return "DrawOval"; } -}; - -class DrawArcOp : public DrawStrokableOp { -public: - DrawArcOp(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) - : DrawStrokableOp(left, top, right, bottom, paint), - mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawArc(mLocalBounds.left, mLocalBounds.top, - mLocalBounds.right, mLocalBounds.bottom, - mStartAngle, mSweepAngle, mUseCenter, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Arc " RECT_STRING ", start %f, sweep %f, useCenter %d", - RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter); - } - - virtual const char* name() override { return "DrawArc"; } - -private: - float mStartAngle; - float mSweepAngle; - bool mUseCenter; -}; - -class DrawPathOp : public DrawBoundedOp { -public: - DrawPathOp(const SkPath* path, const SkPaint* paint) - : DrawBoundedOp(paint), mPath(path) { - float left, top, offset; - uint32_t width, height; - PathCache::computePathBounds(path, paint, left, top, offset, width, height); - left -= offset; - top -= offset; - mLocalBounds.set(left, top, left + width, top + height); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawPath(mPath, mPaint); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - renderer.getCaches().pathCache.precache(mPath, mPaint); - - deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture; - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Path %p in " RECT_STRING, mPath, RECT_ARGS(mLocalBounds)); - } - - virtual const char* name() override { return "DrawPath"; } - -private: - const SkPath* mPath; -}; - -class DrawLinesOp : public DrawBoundedOp { -public: - DrawLinesOp(const float* points, int count, const SkPaint* paint) - : DrawBoundedOp(points, count, paint), - mPoints(points), mCount(count) { - mLocalBounds.outset(strokeWidthOutset()); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawLines(mPoints, mCount, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Lines count %d", mCount); - } - - virtual const char* name() override { return "DrawLines"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = mPaint->isAntiAlias() ? - DeferredDisplayList::kOpBatch_AlphaVertices : - DeferredDisplayList::kOpBatch_Vertices; - } - -protected: - const float* mPoints; - int mCount; -}; - -class DrawPointsOp : public DrawLinesOp { -public: - DrawPointsOp(const float* points, int count, const SkPaint* paint) - : DrawLinesOp(points, count, paint) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawPoints(mPoints, mCount, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Points count %d", mCount); - } - - virtual const char* name() override { return "DrawPoints"; } -}; - -class DrawSomeTextOp : public DrawOp { -public: - DrawSomeTextOp(const glyph_t* text, int bytesCount, int count, const SkPaint* paint) - : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {}; - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw some text, %d bytes", mBytesCount); - } - - virtual bool hasTextShadow() const override { - return PaintUtils::hasTextShadow(mPaint); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer(); - fontRenderer.precache(mPaint, mText, mCount, SkMatrix::I()); - - deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ? - DeferredDisplayList::kOpBatch_Text : - DeferredDisplayList::kOpBatch_ColorText; - } - -protected: - const glyph_t* mText; - int mBytesCount; - int mCount; -}; - -class DrawTextOnPathOp : public DrawSomeTextOp { -public: - DrawTextOnPathOp(const glyph_t* text, int bytesCount, int count, - const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) - : DrawSomeTextOp(text, bytesCount, count, paint), - mPath(path), mHOffset(hOffset), mVOffset(vOffset) { - /* TODO: inherit from DrawBounded and init mLocalBounds */ - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath, - mHOffset, mVOffset, mPaint); - } - - virtual const char* name() override { return "DrawTextOnPath"; } - -private: - const SkPath* mPath; - float mHOffset; - float mVOffset; -}; - -class DrawTextOp : public DrawStrokableOp { -public: - DrawTextOp(const glyph_t* text, int bytesCount, int count, float x, float y, - const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds) - : DrawStrokableOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count), - mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) { - mPrecacheTransform = SkMatrix::InvalidMatrix(); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer(); - SkMatrix transform; - renderer.findBestFontTransform(state.mMatrix, &transform); - if (mPrecacheTransform != transform) { - fontRenderer.precache(mPaint, mText, mCount, transform); - mPrecacheTransform = transform; - } - deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ? - DeferredDisplayList::kOpBatch_Text : - DeferredDisplayList::kOpBatch_ColorText; - - deferInfo.mergeId = reinterpret_cast<mergeid_t>(mPaint->getColor()); - - // don't merge decorated text - the decorations won't draw in order - bool hasDecorations = mPaint->getFlags() - & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag); - - deferInfo.mergeable = state.mMatrix.isPureTranslate() - && !hasDecorations - && PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - Rect bounds; - getLocalBounds(bounds); - renderer.drawText(mText, mBytesCount, mCount, mX, mY, - mPositions, mPaint, mTotalAdvance, bounds); - } - - virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const std::vector<OpStatePair>& ops, const Rect& bounds) override { - for (unsigned int i = 0; i < ops.size(); i++) { - const DeferredDisplayState& state = *(ops[i].state); - DrawOpMode drawOpMode = (i == ops.size() - 1) ? DrawOpMode::kFlush : DrawOpMode::kDefer; - renderer.restoreDisplayState(state, true); // restore all but the clip - - DrawTextOp& op = *((DrawTextOp*)ops[i].op); - // quickReject() will not occure in drawText() so we can use mLocalBounds - // directly, we do not need to account for shadow by calling getLocalBounds() - renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY, - op.mPositions, op.mPaint, op.mTotalAdvance, op.mLocalBounds, - drawOpMode); - } - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount); - } - - virtual const char* name() override { return "DrawText"; } - -private: - const glyph_t* mText; - int mBytesCount; - int mCount; - float mX; - float mY; - const float* mPositions; - float mTotalAdvance; - SkMatrix mPrecacheTransform; -}; - -/////////////////////////////////////////////////////////////////////////////// -// SPECIAL DRAW OPERATIONS -/////////////////////////////////////////////////////////////////////////////// - -class DrawFunctorOp : public DrawOp { -public: - DrawFunctorOp(Functor* functor) - : DrawOp(nullptr), mFunctor(functor) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.startMark("GL functor"); - renderer.callDrawGLFunction(mFunctor, dirty); - renderer.endMark(); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Functor %p", mFunctor); - } - - virtual const char* name() override { return "DrawFunctor"; } - -private: - Functor* mFunctor; -}; - -class DrawRenderNodeOp : public DrawBoundedOp { - friend class RenderNode; // grant RenderNode access to info of child - friend class DisplayList; // grant DisplayList access to info of child - friend class DisplayListCanvas; - friend class TestUtils; -public: - DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple) - : DrawBoundedOp(0, 0, - renderNode->stagingProperties().getWidth(), - renderNode->stagingProperties().getHeight(), - nullptr) - , renderNode(renderNode) - , mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple()) - , localMatrix(transformFromParent) - , skipInOrderDraw(false) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - if (renderNode->isRenderable() && !skipInOrderDraw) { - renderNode->defer(deferStruct, level + 1); - } - } - - virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, - bool useQuickReject) override { - if (renderNode->isRenderable() && !skipInOrderDraw) { - renderNode->replay(replayStruct, level + 1); - } - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - LOG_ALWAYS_FATAL("should not be called, because replay() is overridden"); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw RenderNode %p %s", renderNode, renderNode->getName()); - if (renderNode && (logFlags & kOpLogFlag_Recurse)) { - renderNode->output(level + 1); - } - } - - virtual const char* name() override { return "DrawRenderNode"; } - -private: - RenderNode* renderNode; - - /** - * This RenderNode was drawn into a DisplayList with the canvas in a state that will likely - * require rendering with stencil clipping. Either: - * - * 1) A path clip or rotated rect clip was in effect on the canvas at record time - * 2) The RenderNode was recorded with a non-simple canvas transform (e.g. rotation) - * - * Note: even if this is false, non-rect clipping may still be applied applied either due to - * property-driven rotation (either in this RenderNode, or any ancestor), or record time - * clipping in an ancestor. These are handled in RenderNode::prepareTreeImpl since they are - * dynamic (relative to a static DisplayList of a parent), and don't affect this flag. - */ - bool mRecordedWithPotentialStencilClip; - - /////////////////////////// - // Properties below are used by RenderNode::computeOrderingImpl() and issueOperations() - /////////////////////////// - /** - * Records transform vs parent, used for computing total transform without rerunning DL contents - */ - const mat4 localMatrix; - - /** - * Holds the transformation between the projection surface ViewGroup and this RenderNode - * drawing instance. Represents any translations / transformations done within the drawing of - * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this - * DisplayList draw instance. - * - * Note: doesn't include transformation within the RenderNode, or its properties. - */ - mat4 transformFromCompositingAncestor; - bool skipInOrderDraw; -}; - -/** - * Not a canvas operation, used only by 3d / z ordering logic in RenderNode::iterate() - */ -class DrawShadowOp : public DrawOp { -public: - DrawShadowOp(const mat4& transformXY, const mat4& transformZ, - float casterAlpha, const SkPath* casterOutline) - : DrawOp(nullptr) - , mTransformXY(transformXY) - , mTransformZ(transformZ) - , mCasterAlpha(casterAlpha) - , mCasterOutline(casterOutline) { - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - renderer.getCaches().tessellationCache.precacheShadows(&state.mMatrix, - renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline, - &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius()); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - TessellationCache::vertexBuffer_pair_t buffers; - Matrix4 drawTransform(*(renderer.currentTransform())); - renderer.getCaches().tessellationCache.getShadowBuffers(&drawTransform, - renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline, - &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius(), - buffers); - - renderer.drawShadow(mCasterAlpha, buffers.first, buffers.second); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOGS("DrawShadow"); - } - - virtual const char* name() override { return "DrawShadow"; } - -private: - bool isCasterOpaque() { return mCasterAlpha >= 1.0f; } - - const mat4 mTransformXY; - const mat4 mTransformZ; - const float mCasterAlpha; - const SkPath* mCasterOutline; -}; - -class DrawLayerOp : public DrawOp { -public: - DrawLayerOp(Layer* layer) - : DrawOp(nullptr), mLayer(layer) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawLayer(mLayer); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Layer %p", mLayer); - } - - virtual const char* name() override { return "DrawLayer"; } - -private: - Layer* mLayer; -}; - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_DISPLAY_OPERATION_H diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 276c18d0d3f9..25dc92c8a8dc 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -16,6 +16,9 @@ #include "FontRenderer.h" +#include "BakedOpDispatcher.h" +#include "BakedOpRenderer.h" +#include "BakedOpState.h" #include "Caches.h" #include "Debug.h" #include "Extensions.h" @@ -27,15 +30,6 @@ #include "utils/Blur.h" #include "utils/Timing.h" - -#if HWUI_NEW_OPS -#include "BakedOpDispatcher.h" -#include "BakedOpRenderer.h" -#include "BakedOpState.h" -#else -#include "OpenGLRenderer.h" -#endif - #include <algorithm> #include <cutils/properties.h> #include <SkGlyph.h> @@ -67,7 +61,6 @@ void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) { int transformFlags = pureTranslate ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None; Glop glop; -#if HWUI_NEW_OPS GlopBuilder(renderer->renderState(), renderer->caches(), &glop) .setRoundRectClipState(bakedState->roundRectClipState) .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount()) @@ -77,16 +70,6 @@ void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) { .build(); // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer renderer->renderGlop(nullptr, clip, glop); -#else - GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop) - .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState) - .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount()) - .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha) - .setTransform(*(renderer->currentSnapshot()), transformFlags) - .setModelViewOffsetRect(0, 0, Rect()) - .build(); - renderer->renderGlop(glop); -#endif } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index e10a81b8ccd8..dedc4944299d 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_FONT_RENDERER_H -#define ANDROID_HWUI_FONT_RENDERER_H +#pragma once #include "font/FontUtil.h" #include "font/CacheTexture.h" @@ -44,31 +43,21 @@ namespace RSC { namespace android { namespace uirenderer { -#if HWUI_NEW_OPS class BakedOpState; class BakedOpRenderer; struct ClipBase; -#else -class OpenGLRenderer; -#endif class TextDrawFunctor { public: TextDrawFunctor( -#if HWUI_NEW_OPS BakedOpRenderer* renderer, const BakedOpState* bakedState, const ClipBase* clip, -#else - OpenGLRenderer* renderer, -#endif float x, float y, bool pureTranslate, int alpha, SkXfermode::Mode mode, const SkPaint* paint) : renderer(renderer) -#if HWUI_NEW_OPS , bakedState(bakedState) , clip(clip) -#endif , x(x) , y(y) , pureTranslate(pureTranslate) @@ -79,13 +68,9 @@ public: void draw(CacheTexture& texture, bool linearFiltering); -#if HWUI_NEW_OPS BakedOpRenderer* renderer; const BakedOpState* bakedState; const ClipBase* clip; -#else - OpenGLRenderer* renderer; -#endif float x; float y; bool pureTranslate; @@ -218,5 +203,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_FONT_RENDERER_H diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index 37d9d0e749e6..be4fdac5f800 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -477,7 +477,7 @@ void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) { projectionReceiverOutline->transform( skCurrentTransform, &transformedMaskPath); - mCanvasState.setProjectionPathMask(mAllocator, &transformedMaskPath); + mCanvasState.setProjectionPathMask(&transformedMaskPath); } for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) { diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp index adadd32a2fc0..570322dfb4eb 100644 --- a/libs/hwui/FrameInfoVisualizer.cpp +++ b/libs/hwui/FrameInfoVisualizer.cpp @@ -15,11 +15,7 @@ */ #include "FrameInfoVisualizer.h" -#if HWUI_NEW_OPS #include "BakedOpRenderer.h" -#else -#include "OpenGLRenderer.h" -#endif #include "utils/Color.h" #include <cutils/compiler.h> diff --git a/libs/hwui/FrameInfoVisualizer.h b/libs/hwui/FrameInfoVisualizer.h index 83adf1985c72..fc958b8b414a 100644 --- a/libs/hwui/FrameInfoVisualizer.h +++ b/libs/hwui/FrameInfoVisualizer.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef DRAWPROFILER_H -#define DRAWPROFILER_H + +#pragma once #include "FrameInfo.h" #include "Properties.h" @@ -28,13 +28,8 @@ namespace android { namespace uirenderer { -#if HWUI_NEW_OPS class BakedOpRenderer; typedef BakedOpRenderer ContentRenderer; -#else -class OpenGLRenderer; -typedef OpenGLRenderer ContentRenderer; -#endif // TODO: This is a bit awkward as it needs to match the thing in CanvasContext // A better abstraction here would be nice but iterators are painful @@ -93,5 +88,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* DRAWPROFILER_H */ diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h index 6433c86908e7..46dd598711b8 100644 --- a/libs/hwui/Glop.h +++ b/libs/hwui/Glop.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_GLOP_H -#define ANDROID_HWUI_GLOP_H +#pragma once #include "FloatColor.h" #include "Matrix.h" @@ -68,7 +67,7 @@ namespace TransformFlags { OffsetByFudgeFactor = 1 << 0, // Canvas transform isn't applied to the mesh at draw time, - //since it's already built in. + // since it's already built in. MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS }; }; @@ -168,14 +167,6 @@ public: GLenum dst; } blend; -#if !HWUI_NEW_OPS - /** - * Bounds of the drawing command in layer space. Only mapped into layer - * space once GlopBuilder::build() is called. - */ - Rect bounds; // TODO: remove for HWUI_NEW_OPS -#endif - /** * Additional render state to enumerate: * - scissor + (bits for whether each of LTRB needed?) @@ -185,5 +176,3 @@ public: } /* namespace uirenderer */ } /* namespace android */ - -#endif // ANDROID_HWUI_GLOP_H diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index e502725ddb09..1091736ab9c3 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -17,8 +17,10 @@ #include "Caches.h" #include "Glop.h" +#include "Layer.h" #include "Matrix.h" #include "Patch.h" +#include "PathCache.h" #include "renderstate/MeshState.h" #include "renderstate/RenderState.h" #include "SkiaShader.h" @@ -165,20 +167,6 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, return *this; } -GlopBuilder& GlopBuilder::setMeshTexturedMesh(TextureVertex* vertexData, int elementCount) { - TRIGGER_STAGE(kMeshStage); - - mOutGlop->mesh.primitiveMode = GL_TRIANGLES; - mOutGlop->mesh.indices = { 0, nullptr }; - mOutGlop->mesh.vertices = { - 0, - VertexAttribFlags::TextureCoord, - &vertexData[0].x, &vertexData[0].u, nullptr, - kTextureVertexStride }; - mOutGlop->mesh.elementCount = elementCount; - return *this; -} - GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount) { TRIGGER_STAGE(kMeshStage); @@ -514,9 +502,6 @@ GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) { mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f); mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); -#if !HWUI_NEW_OPS - mOutGlop->bounds = destination; -#endif return *this; } @@ -540,9 +525,6 @@ GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f); mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); -#if !HWUI_NEW_OPS - mOutGlop->bounds = destination; -#endif return *this; } @@ -550,10 +532,6 @@ GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, c TRIGGER_STAGE(kModelViewStage); mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); -#if !HWUI_NEW_OPS - mOutGlop->bounds = source; - mOutGlop->bounds.translate(offsetX, offsetY); -#endif return *this; } @@ -573,10 +551,6 @@ GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offset } mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); -#if !HWUI_NEW_OPS - mOutGlop->bounds = source; - mOutGlop->bounds.translate(offsetX, offsetY); -#endif return *this; } @@ -676,9 +650,6 @@ void GlopBuilder::build() { // Final step: populate program and map bounds into render target space mOutGlop->fill.program = mCaches.programCache.get(mDescription); -#if !HWUI_NEW_OPS - mOutGlop->transform.meshTransform().mapRect(mOutGlop->bounds); -#endif } void GlopBuilder::dump(const Glop& glop) { @@ -718,9 +689,6 @@ void GlopBuilder::dump(const Glop& glop) { ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState); ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst); -#if !HWUI_NEW_OPS - ALOGD("Glop bounds " RECT_STRING, RECT_ARGS(glop.bounds)); -#endif } } /* namespace uirenderer */ diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h index 1c520c26110e..11524615074e 100644 --- a/libs/hwui/GlopBuilder.h +++ b/libs/hwui/GlopBuilder.h @@ -13,11 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef RENDERSTATE_GLOPBUILDER_H -#define RENDERSTATE_GLOPBUILDER_H + +#pragma once #include "Glop.h" -#include "OpenGLRenderer.h" #include "Program.h" #include "renderstate/Blend.h" #include "utils/Macros.h" @@ -30,9 +29,13 @@ namespace uirenderer { class Caches; class Matrix4; +class Patch; class RenderState; class Texture; +class UvMapper; class VertexBuffer; +struct PathTexture; +struct ShadowTexture; namespace TextureFillFlags { enum { @@ -53,7 +56,6 @@ public: GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs); GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer); GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount); - GlopBuilder& setMeshTexturedMesh(TextureVertex* vertexData, int elementCount); // TODO: delete GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount); // TODO: use indexed quads GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount GlopBuilder& setMeshPatchQuads(const Patch& patch); @@ -75,9 +77,6 @@ public: // Similarly setFillLayer normally forces its own wrap & filter mode GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform); - GlopBuilder& setTransform(const Snapshot& snapshot, const int transformFlags) { - return setTransform(*snapshot.transform, transformFlags); - } GlopBuilder& setTransform(const Matrix4& canvas, const int transformFlags); GlopBuilder& setModelViewMapUnitToRect(const Rect destination); @@ -133,5 +132,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif // RENDERSTATE_GLOPBUILDER_H diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index cdbbbab7730d..b911b6825226 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -17,9 +17,6 @@ #include "Layer.h" #include "Caches.h" -#include "DeferredDisplayList.h" -#include "LayerRenderer.h" -#include "OpenGLRenderer.h" #include "RenderNode.h" #include "renderstate/RenderState.h" #include "utils/TraceUtils.h" @@ -35,13 +32,12 @@ namespace android { namespace uirenderer { -Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight) +Layer::Layer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight) : GpuMemoryTracker(GpuObjectType::Layer) , state(State::Uncached) , caches(Caches::getInstance()) , renderState(renderState) - , texture(caches) - , type(layerType) { + , texture(caches) { // TODO: This is a violation of Android's typical ref counting, but it // preserves the old inc/dec ref locations. This should be changed... incStrong(nullptr); @@ -55,125 +51,15 @@ Layer::~Layer() { renderState.unregisterLayer(this); SkSafeUnref(colorFilter); - if (stencil || fbo || texture.mId) { - removeFbo(); + if (texture.mId) { texture.deleteTexture(); } - - delete[] mesh; } void Layer::onGlContextLost() { - removeFbo(); texture.deleteTexture(); } -uint32_t Layer::computeIdealWidth(uint32_t layerWidth) { - return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE); -} - -uint32_t Layer::computeIdealHeight(uint32_t layerHeight) { - return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE); -} - -void Layer::requireRenderer() { - if (!renderer) { - renderer.reset(new LayerRenderer(renderState, this)); - renderer->initProperties(); - } -} - -void Layer::updateLightPosFromRenderer(const OpenGLRenderer& rootRenderer) { - if (renderer && rendererLightPosDirty) { - // re-init renderer's light position, based upon last cached location in window - Vector3 lightPos = rootRenderer.getLightCenter(); - cachedInvTransformInWindow.mapPoint3d(lightPos); - renderer->initLight(rootRenderer.getLightRadius(), - rootRenderer.getAmbientShadowAlpha(), - rootRenderer.getSpotShadowAlpha()); - renderer->setLightCenter(lightPos); - rendererLightPosDirty = false; - } -} - -bool Layer::resize(const uint32_t width, const uint32_t height) { - uint32_t desiredWidth = computeIdealWidth(width); - uint32_t desiredHeight = computeIdealWidth(height); - - if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) { - return true; - } - - ATRACE_NAME("resizeLayer"); - - const uint32_t maxTextureSize = caches.maxTextureSize; - if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) { - ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)", - desiredWidth, desiredHeight, maxTextureSize, maxTextureSize); - return false; - } - - uint32_t oldWidth = getWidth(); - uint32_t oldHeight = getHeight(); - - setSize(desiredWidth, desiredHeight); - - if (fbo) { - caches.textureState().activateTexture(0); - bindTexture(); - allocateTexture(); - - if (glGetError() != GL_NO_ERROR) { - setSize(oldWidth, oldHeight); - return false; - } - } - - if (stencil) { - stencil->bind(); - stencil->resize(desiredWidth, desiredHeight); - - if (glGetError() != GL_NO_ERROR) { - setSize(oldWidth, oldHeight); - return false; - } - } - - return true; -} - -void Layer::removeFbo(bool flush) { - if (stencil) { - GLuint previousFbo = renderState.getFramebuffer(); - renderState.bindFramebuffer(fbo); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); - renderState.bindFramebuffer(previousFbo); - - caches.renderBufferCache.put(stencil); - stencil = nullptr; - } - - if (fbo) { - if (flush) LayerRenderer::flushLayer(renderState, this); - renderState.deleteFramebuffer(fbo); - fbo = 0; - } -} - -void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom) { - requireRenderer(); - this->renderNode = renderNode; - const Rect r(left, top, right, bottom); - dirtyRect.unionWith(r); - deferredUpdateScheduled = true; -} - -void Layer::setPaint(const SkPaint* paint) { - alpha = PaintUtils::getAlphaDirect(paint); - mode = PaintUtils::getXfermodeDirect(paint); - setColorFilter((paint) ? paint->getColorFilter() : nullptr); -} - void Layer::setColorFilter(SkColorFilter* filter) { SkRefCnt_SafeAssign(colorFilter, filter); } @@ -184,12 +70,6 @@ void Layer::bindTexture() const { } } -void Layer::bindStencilRenderBuffer() const { - if (stencil) { - stencil->bind(); - } -} - void Layer::generateTexture() { if (!texture.mId) { glGenTextures(1, &texture.mId); @@ -206,86 +86,6 @@ void Layer::clearTexture() { texture.mId = 0; } -void Layer::allocateTexture() { -#if DEBUG_LAYERS - ALOGD(" Allocate layer: %dx%d", getWidth(), getHeight()); -#endif - if (texture.mId) { - texture.updateSize(getWidth(), getHeight(), GL_RGBA); - glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0, - GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } -} - -void Layer::defer(const OpenGLRenderer& rootRenderer) { - ATRACE_LAYER_WORK("Optimize"); - - updateLightPosFromRenderer(rootRenderer); - const float width = layer.getWidth(); - const float height = layer.getHeight(); - - if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 && - dirtyRect.right >= width && dirtyRect.bottom >= height)) { - dirtyRect.set(0, 0, width, height); - } - - deferredList.reset(new DeferredDisplayList(dirtyRect)); - - DeferStateStruct deferredState(*deferredList, *renderer, - RenderNode::kReplayFlag_ClipChildren); - - renderer->setupFrameState(width, height, dirtyRect.left, dirtyRect.top, - dirtyRect.right, dirtyRect.bottom, !isBlend()); - - renderNode->computeOrdering(); - renderNode->defer(deferredState, 0); - - deferredUpdateScheduled = false; -} - -void Layer::cancelDefer() { - renderNode = nullptr; - deferredUpdateScheduled = false; - deferredList.reset(nullptr); -} - -void Layer::flush() { - // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled - if (deferredList && renderer) { - ATRACE_LAYER_WORK("Issue"); - renderer->startMark((renderNode.get() != nullptr) ? renderNode->getName() : "Layer"); - - renderer->prepareDirty(layer.getWidth(), layer.getHeight(), - dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend()); - - deferredList->flush(*renderer, dirtyRect); - - renderer->finish(); - - dirtyRect.setEmpty(); - renderNode = nullptr; - - renderer->endMark(); - } -} - -void Layer::render(const OpenGLRenderer& rootRenderer) { - ATRACE_LAYER_WORK("Direct-Issue"); - - updateLightPosFromRenderer(rootRenderer); - renderer->prepareDirty(layer.getWidth(), layer.getHeight(), - dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend()); - - renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren); - - renderer->finish(); - - dirtyRect.setEmpty(); - - deferredUpdateScheduled = false; - renderNode = nullptr; -} - void Layer::postDecStrong() { renderState.postDecStrong(this); } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 1e5498bb3d21..153184149db6 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_LAYER_H -#define ANDROID_HWUI_LAYER_H +#pragma once #include <cutils/compiler.h> #include <sys/types.h> @@ -46,22 +45,13 @@ namespace uirenderer { // Forward declarations class Caches; -class RenderNode; class RenderState; -class OpenGLRenderer; -class DeferredDisplayList; -struct DeferStateStruct; /** * A layer has dimensions and is backed by an OpenGL texture or FBO. */ class Layer : public VirtualLightRefBase, GpuMemoryTracker { public: - enum class Type { - Texture, - DisplayList, - }; - // layer lifecycle, controlled from outside enum class State { Uncached = 0, @@ -73,45 +63,9 @@ public: }; State state; // public for logging/debugging purposes - Layer(Type type, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight); + Layer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight); ~Layer(); - static uint32_t computeIdealWidth(uint32_t layerWidth); - static uint32_t computeIdealHeight(uint32_t layerHeight); - - /** - * Calling this method will remove (either by recycling or - * destroying) the associated FBO, if present, and any render - * buffer (stencil for instance.) - */ - void removeFbo(bool flush = true); - - /** - * Sets this layer's region to a rectangle. Computes the appropriate - * texture coordinates. - */ - void setRegionAsRect() { - const android::Rect& bounds = region.getBounds(); - regionRect.set(bounds.leftTop().x, bounds.leftTop().y, - bounds.rightBottom().x, bounds.rightBottom().y); - - const float texX = 1.0f / float(texture.mWidth); - const float texY = 1.0f / float(texture.mHeight); - const float height = layer.getHeight(); - texCoords.set( - regionRect.left * texX, (height - regionRect.top) * texY, - regionRect.right * texX, (height - regionRect.bottom) * texY); - - regionRect.translate(layer.left, layer.top); - } - - void setWindowTransform(Matrix4& windowTransform) { - cachedInvTransformInWindow.loadInverse(windowTransform); - rendererLightPosDirty = true; - } - - void updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom); - inline uint32_t getWidth() const { return texture.mWidth; } @@ -120,23 +74,10 @@ public: return texture.mHeight; } - /** - * Resize the layer and its texture if needed. - * - * @param width The new width of the layer - * @param height The new height of the layer - * - * @return True if the layer was resized or nothing happened, false if - * a failure occurred during the resizing operation - */ - bool resize(const uint32_t width, const uint32_t height); - void setSize(uint32_t width, uint32_t height) { texture.updateSize(width, height, texture.format()); } - ANDROID_API void setPaint(const SkPaint* paint); - inline void setBlend(bool blend) { texture.blend = blend; } @@ -170,36 +111,6 @@ public: return mode; } - inline void setEmpty(bool empty) { - this->empty = empty; - } - - inline bool isEmpty() const { - return empty; - } - - inline void setFbo(GLuint fbo) { - this->fbo = fbo; - } - - inline GLuint getFbo() const { - return fbo; - } - - inline void setStencilRenderBuffer(RenderBuffer* renderBuffer) { - if (RenderBuffer::isStencilBuffer(renderBuffer->getFormat())) { - this->stencil = renderBuffer; - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, stencil->getName()); - } else { - ALOGE("The specified render buffer is not a stencil buffer"); - } - } - - inline RenderBuffer* getStencilRenderBuffer() const { - return stencil; - } - inline GLuint getTextureId() const { return texture.id(); } @@ -228,52 +139,21 @@ public: texture.setFilter(filter, bindTexture, force, renderTarget); } - inline bool isCacheable() const { - return cacheable; - } - - inline void setCacheable(bool cacheable) { - this->cacheable = cacheable; - } - - inline bool isDirty() const { - return dirty; - } - - inline void setDirty(bool dirty) { - this->dirty = dirty; - } - - inline bool isTextureLayer() const { - return type == Type::Texture; - } - inline SkColorFilter* getColorFilter() const { return colorFilter; } - ANDROID_API void setColorFilter(SkColorFilter* filter); - - inline void setConvexMask(const SkPath* convexMask) { - this->convexMask = convexMask; - } - - inline const SkPath* getConvexMask() { - return convexMask; - } - - void bindStencilRenderBuffer() const; + void setColorFilter(SkColorFilter* filter); void bindTexture() const; void generateTexture(); - void allocateTexture(); /** * When the caller frees the texture itself, the caller * must call this method to tell this layer that it lost * the texture. */ - ANDROID_API void clearTexture(); + void clearTexture(); inline mat4& getTexTransform() { return texTransform; @@ -283,11 +163,6 @@ public: return transform; } - void defer(const OpenGLRenderer& rootRenderer); - void cancelDefer(); - void flush(); - void render(const OpenGLRenderer& rootRenderer); - /** * Posts a decStrong call to the appropriate thread. * Thread-safe. @@ -313,80 +188,17 @@ public: */ Rect clipRect; - /** - * Dirty region indicating what parts of the layer - * have been drawn. - */ - Region region; - /** - * If the region is a rectangle, coordinates of the - * region are stored here. - */ - Rect regionRect; - - /** - * If the layer can be rendered as a mesh, this is non-null. - */ - TextureVertex* mesh = nullptr; - GLsizei meshElementCount = 0; - - /** - * Used for deferred updates. - */ - bool deferredUpdateScheduled = false; - std::unique_ptr<OpenGLRenderer> renderer; - sp<RenderNode> renderNode; - Rect dirtyRect; - bool debugDrawUpdate = false; - bool hasDrawnSinceUpdate = false; - bool wasBuildLayered = false; - private: - void requireRenderer(); - void updateLightPosFromRenderer(const OpenGLRenderer& rootRenderer); - Caches& caches; RenderState& renderState; /** - * Name of the FBO used to render the layer. If the name is 0 - * this layer is not backed by an FBO, but a simple texture. - */ - GLuint fbo = 0; - - /** - * The render buffer used as the stencil buffer. - */ - RenderBuffer* stencil = nullptr; - - /** - * Indicates whether this layer has been used already. - */ - bool empty = true; - - /** * The texture backing this layer. */ Texture texture; /** - * If set to true (by default), the layer can be reused. - */ - bool cacheable = true; - - /** - * Denotes whether the layer is a DisplayList, or Texture layer. - */ - const Type type; - - /** - * When set to true, this layer is dirty and should be cleared - * before any rendering occurs. - */ - bool dirty = false; - - /** * Indicates the render target. */ GLenum renderTarget = GL_TEXTURE_2D; @@ -421,28 +233,7 @@ private: */ mat4 transform; - /** - * Cached transform of layer in window, updated only on creation / resize - */ - mat4 cachedInvTransformInWindow; - bool rendererLightPosDirty = true; - - /** - * Used to defer display lists when the layer is updated with a - * display list. - */ - std::unique_ptr<DeferredDisplayList> deferredList; - - /** - * This convex path should be used to mask the layer's draw to the screen. - * - * Data not owned/managed by layer object. - */ - const SkPath* convexMask = nullptr; - }; // struct Layer }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_LAYER_H diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp deleted file mode 100644 index f5681ce712d5..000000000000 --- a/libs/hwui/LayerCache.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "LayerCache.h" - -#include "Caches.h" -#include "Properties.h" - -#include <utils/Log.h> - -#include <GLES2/gl2.h> - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -LayerCache::LayerCache() - : mSize(0) - , mMaxSize(Properties::layerPoolSize) {} - -LayerCache::~LayerCache() { - clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management -/////////////////////////////////////////////////////////////////////////////// - -size_t LayerCache::getCount() { - return mCache.size(); -} - -uint32_t LayerCache::getSize() { - return mSize; -} - -uint32_t LayerCache::getMaxSize() { - return mMaxSize; -} - -void LayerCache::setMaxSize(uint32_t maxSize) { - clear(); - mMaxSize = maxSize; -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -int LayerCache::LayerEntry::compare(const LayerCache::LayerEntry& lhs, - const LayerCache::LayerEntry& rhs) { - int deltaInt = int(lhs.mWidth) - int(rhs.mWidth); - if (deltaInt != 0) return deltaInt; - - return int(lhs.mHeight) - int(rhs.mHeight); -} - -void LayerCache::deleteLayer(Layer* layer) { - if (layer) { - LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(), - layer->getFbo()); - mSize -= layer->getWidth() * layer->getHeight() * 4; - layer->state = Layer::State::DeletedFromCache; - layer->decStrong(nullptr); - } -} - -void LayerCache::clear() { - for (auto entry : mCache) { - deleteLayer(entry.mLayer); - } - mCache.clear(); -} - -Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uint32_t height) { - Layer* layer = nullptr; - - LayerEntry entry(width, height); - auto iter = mCache.find(entry); - - if (iter != mCache.end()) { - entry = *iter; - mCache.erase(iter); - - layer = entry.mLayer; - layer->state = Layer::State::RemovedFromCache; - mSize -= layer->getWidth() * layer->getHeight() * 4; - - LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight()); - } else { - LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight); - - layer = new Layer(Layer::Type::DisplayList, renderState, entry.mWidth, entry.mHeight); - layer->setBlend(true); - layer->generateTexture(); - layer->bindTexture(); - layer->setFilter(GL_NEAREST); - layer->setWrap(GL_CLAMP_TO_EDGE, false); - -#if DEBUG_LAYERS - dump(); -#endif - } - - return layer; -} - -void LayerCache::dump() { - for (auto entry : mCache) { - ALOGD(" Layer size %dx%d", entry.mWidth, entry.mHeight); - } -} - -bool LayerCache::put(Layer* layer) { - if (!layer->isCacheable()) return false; - - const uint32_t size = layer->getWidth() * layer->getHeight() * 4; - // Don't even try to cache a layer that's bigger than the cache - if (size < mMaxSize) { - // TODO: Use an LRU - while (mSize + size > mMaxSize) { - Layer* victim = mCache.begin()->mLayer; - deleteLayer(victim); - mCache.erase(mCache.begin()); - - LAYER_LOGD(" Deleting layer %.2fx%.2f", victim->layer.getWidth(), - victim->layer.getHeight()); - } - - layer->cancelDefer(); - - LayerEntry entry(layer); - - mCache.insert(entry); - mSize += size; - - layer->state = Layer::State::InCache; - return true; - } - - layer->state = Layer::State::FailedToCache; - return false; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h deleted file mode 100644 index 6fe7b3aae859..000000000000 --- a/libs/hwui/LayerCache.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_LAYER_CACHE_H -#define ANDROID_HWUI_LAYER_CACHE_H - -#include "Debug.h" -#include "Layer.h" - -#include <set> - -namespace android { -namespace uirenderer { - -class RenderState; - -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -#if DEBUG_LAYERS - #define LAYER_LOGD(...) ALOGD(__VA_ARGS__) -#else - #define LAYER_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Cache -/////////////////////////////////////////////////////////////////////////////// - -class LayerCache { -public: - LayerCache(); - ~LayerCache(); - - /** - * Returns a layer large enough for the specified dimensions. If no suitable - * layer can be found, a new one is created and returned. If creating a new - * layer fails, NULL is returned. - * - * When a layer is obtained from the cache, it is removed and the total - * size of the cache goes down. - * - * @param width The desired width of the layer - * @param height The desired height of the layer - */ - Layer* get(RenderState& renderState, const uint32_t width, const uint32_t height); - - /** - * Adds the layer to the cache. The layer will not be added if there is - * not enough space available. Adding a layer can cause other layers to - * be removed from the cache. - * - * @param layer The layer to add to the cache - * - * @return True if the layer was added, false otherwise. - */ - bool put(Layer* layer); - /** - * Clears the cache. This causes all layers to be deleted. - */ - void clear(); - - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); - /** - * Returns the maximum size of the cache in bytes. - */ - uint32_t getMaxSize(); - /** - * Returns the current size of the cache in bytes. - */ - uint32_t getSize(); - - size_t getCount(); - - /** - * Prints out the content of the cache. - */ - void dump(); - -private: - struct LayerEntry { - LayerEntry(): - mLayer(nullptr), mWidth(0), mHeight(0) { - } - - LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(nullptr) { - mWidth = Layer::computeIdealWidth(layerWidth); - mHeight = Layer::computeIdealHeight(layerHeight); - } - - LayerEntry(Layer* layer): - mLayer(layer), mWidth(layer->getWidth()), mHeight(layer->getHeight()) { - } - - static int compare(const LayerEntry& lhs, const LayerEntry& rhs); - - bool operator==(const LayerEntry& other) const { - return compare(*this, other) == 0; - } - - bool operator!=(const LayerEntry& other) const { - return compare(*this, other) != 0; - } - - bool operator<(const LayerEntry& other) const { - return LayerEntry::compare(*this, other) < 0; - } - - Layer* mLayer; - uint32_t mWidth; - uint32_t mHeight; - }; // struct LayerEntry - - void deleteLayer(Layer* layer); - - std::multiset<LayerEntry> mCache; - - uint32_t mSize; - uint32_t mMaxSize; -}; // class LayerCache - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_LAYER_CACHE_H diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 137316f57725..8d50dc2ccd94 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include "LayerCache.h" #include "LayerRenderer.h" #include "Matrix.h" #include "Properties.h" @@ -27,257 +26,15 @@ #include <private/hwui/DrawGlInfo.h> - namespace android { namespace uirenderer { -/////////////////////////////////////////////////////////////////////////////// -// Rendering -/////////////////////////////////////////////////////////////////////////////// - -LayerRenderer::LayerRenderer(RenderState& renderState, Layer* layer) - : OpenGLRenderer(renderState) - , mLayer(layer) { -} - -LayerRenderer::~LayerRenderer() { -} - -void LayerRenderer::prepareDirty(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque) { - LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo()); - - mRenderState.bindFramebuffer(mLayer->getFbo()); - - const float width = mLayer->layer.getWidth(); - const float height = mLayer->layer.getHeight(); - - Rect dirty(left, top, right, bottom); - if (dirty.isEmpty() || (dirty.left <= 0 && dirty.top <= 0 && - dirty.right >= width && dirty.bottom >= height)) { - mLayer->region.clear(); - dirty.set(0.0f, 0.0f, width, height); - } else { - dirty.doIntersect(0.0f, 0.0f, width, height); - android::Rect r(dirty.left, dirty.top, dirty.right, dirty.bottom); - mLayer->region.subtractSelf(r); - } - mLayer->clipRect.set(dirty); - - OpenGLRenderer::prepareDirty(viewportWidth, viewportHeight, - dirty.left, dirty.top, dirty.right, dirty.bottom, opaque); -} - -void LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) { - if (mLayer->isDirty()) { - mRenderState.scissor().setEnabled(false); - glClear(GL_COLOR_BUFFER_BIT); - - mRenderState.scissor().reset(); - mLayer->setDirty(false); - } else { - OpenGLRenderer::clear(left, top, right, bottom, opaque); - } -} - -bool LayerRenderer::finish() { - bool retval = OpenGLRenderer::finish(); - - generateMesh(); - - LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->getFbo()); - - // No need to unbind our FBO, this will be taken care of by the caller - // who will invoke OpenGLRenderer::resume() - return retval; -} - -GLuint LayerRenderer::getTargetFbo() const { - return mLayer->getFbo(); -} - -bool LayerRenderer::suppressErrorChecks() const { - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// Layer support -/////////////////////////////////////////////////////////////////////////////// - -bool LayerRenderer::hasLayer() const { - return true; -} - -void LayerRenderer::ensureStencilBuffer() { - attachStencilBufferToLayer(mLayer); -} - -/////////////////////////////////////////////////////////////////////////////// -// Dirty region tracking -/////////////////////////////////////////////////////////////////////////////// - -Region* LayerRenderer::getRegion() const { - if (mState.currentFlags() & Snapshot::kFlagFboTarget) { - return OpenGLRenderer::getRegion(); - } - return &mLayer->region; -} - -// TODO: This implementation uses a very simple approach to fixing T-junctions which keeps the -// results as rectangles, and is thus not necessarily efficient in the geometry -// produced. Eventually, it may be better to develop triangle-based mechanism. -void LayerRenderer::generateMesh() { - if (mLayer->region.isRect() || mLayer->region.isEmpty()) { - if (mLayer->mesh) { - delete[] mLayer->mesh; - mLayer->mesh = nullptr; - mLayer->meshElementCount = 0; - } - - mLayer->setRegionAsRect(); - return; - } - - // avoid T-junctions as they cause artifacts in between the resultant - // geometry when complex transforms occur. - // TODO: generate the safeRegion only if necessary based on drawing transform (see - // OpenGLRenderer::composeLayerRegion()) - Region safeRegion = Region::createTJunctionFreeRegion(mLayer->region); - - size_t count; - const android::Rect* rects = safeRegion.getArray(&count); - - GLsizei elementCount = count * 6; - - if (mLayer->mesh && mLayer->meshElementCount < elementCount) { - delete[] mLayer->mesh; - mLayer->mesh = nullptr; - } - - if (!mLayer->mesh) { - mLayer->mesh = new TextureVertex[count * 4]; - } - mLayer->meshElementCount = elementCount; - - const float texX = 1.0f / float(mLayer->getWidth()); - const float texY = 1.0f / float(mLayer->getHeight()); - const float height = mLayer->layer.getHeight(); - - TextureVertex* mesh = mLayer->mesh; - - for (size_t i = 0; i < count; i++) { - const android::Rect* r = &rects[i]; - - const float u1 = r->left * texX; - const float v1 = (height - r->top) * texY; - const float u2 = r->right * texX; - const float v2 = (height - r->bottom) * texY; - - TextureVertex::set(mesh++, r->left, r->top, u1, v1); - TextureVertex::set(mesh++, r->right, r->top, u2, v1); - TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); - TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Layers management -/////////////////////////////////////////////////////////////////////////////// - -Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height) { - ATRACE_FORMAT("Allocate %ux%u HW Layer", width, height); - LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height); - - Caches& caches = Caches::getInstance(); - GLuint fbo = renderState.createFramebuffer(); - if (!fbo) { - ALOGW("Could not obtain an FBO"); - return nullptr; - } - - caches.textureState().activateTexture(0); - Layer* layer = caches.layerCache.get(renderState, width, height); - if (!layer) { - ALOGW("Could not obtain a layer"); - return nullptr; - } - - // We first obtain a layer before comparing against the max texture size - // because layers are not allocated at the exact desired size. They are - // always created slightly larger to improve recycling - const uint32_t maxTextureSize = caches.maxTextureSize; - if (layer->getWidth() > maxTextureSize || layer->getHeight() > maxTextureSize) { - ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)", - width, height, maxTextureSize, maxTextureSize); - - // Creating a new layer always increment its refcount by 1, this allows - // us to destroy the layer object if one was created for us - layer->decStrong(nullptr); - - return nullptr; - } - - layer->setFbo(fbo); - layer->layer.set(0.0f, 0.0f, width, height); - layer->texCoords.set(0.0f, height / float(layer->getHeight()), - width / float(layer->getWidth()), 0.0f); - layer->setAlpha(255, SkXfermode::kSrcOver_Mode); - layer->setColorFilter(nullptr); - layer->setDirty(true); - layer->region.clear(); - - GLuint previousFbo = renderState.getFramebuffer(); - - renderState.bindFramebuffer(layer->getFbo()); - layer->bindTexture(); - - // Initialize the texture if needed - if (layer->isEmpty()) { - layer->setEmpty(false); - layer->allocateTexture(); - - // This should only happen if we run out of memory - if (CC_UNLIKELY(GLUtils::dumpGLErrors())) { - LOG_ALWAYS_FATAL("Could not allocate texture for layer (fbo=%d %dx%d)", - fbo, width, height); - renderState.bindFramebuffer(previousFbo); - layer->decStrong(nullptr); - return nullptr; - } - } - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - layer->getTextureId(), 0); - - renderState.bindFramebuffer(previousFbo); - - return layer; -} - -bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { - if (layer) { - LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height); - - if (layer->resize(width, height)) { - layer->layer.set(0.0f, 0.0f, width, height); - layer->texCoords.set(0.0f, height / float(layer->getHeight()), - width / float(layer->getWidth()), 0.0f); - } else { - return false; - } - } - - return true; -} - Layer* LayerRenderer::createTextureLayer(RenderState& renderState) { LAYER_RENDERER_LOGD("Creating new texture layer"); - Layer* layer = new Layer(Layer::Type::Texture, renderState, 0, 0); - layer->setCacheable(false); + Layer* layer = new Layer(renderState, 0, 0); layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f); layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f); - layer->region.clear(); layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer() Caches::getInstance().textureState().activateTexture(0); @@ -287,178 +44,19 @@ Layer* LayerRenderer::createTextureLayer(RenderState& renderState) { } void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, - bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform) { - if (layer) { - layer->setBlend(!isOpaque); - layer->setForceFilter(forceFilter); - layer->setSize(width, height); - layer->layer.set(0.0f, 0.0f, width, height); - layer->region.set(width, height); - layer->regionRect.set(0.0f, 0.0f, width, height); - layer->getTexTransform().load(textureTransform); - - if (renderTarget != layer->getRenderTarget()) { - layer->setRenderTarget(renderTarget); - layer->bindTexture(); - layer->setFilter(GL_NEAREST, false, true); - layer->setWrap(GL_CLAMP_TO_EDGE, false, true); - } - } -} - -void LayerRenderer::destroyLayer(Layer* layer) { - if (layer) { - ATRACE_FORMAT("Destroy %ux%u HW Layer", layer->getWidth(), layer->getHeight()); - LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d", - layer->getWidth(), layer->getHeight(), layer->getFbo()); - - if (!Caches::getInstance().layerCache.put(layer)) { - LAYER_RENDERER_LOGD(" Destroyed!"); - layer->decStrong(nullptr); - } else { - LAYER_RENDERER_LOGD(" Cached!"); -#if DEBUG_LAYER_RENDERER - Caches::getInstance().layerCache.dump(); -#endif - layer->removeFbo(); - layer->region.clear(); - } - } -} - -void LayerRenderer::flushLayer(RenderState& renderState, Layer* layer) { -#ifdef GL_EXT_discard_framebuffer - if (!layer) return; - - GLuint fbo = layer->getFbo(); - if (fbo) { - // If possible, discard any enqueud operations on deferred - // rendering architectures - if (Caches::getInstance().extensions().hasDiscardFramebuffer()) { - GLuint previousFbo = renderState.getFramebuffer(); - if (fbo != previousFbo) { - renderState.bindFramebuffer(fbo); - } - - const GLenum attachments[] = { GL_COLOR_ATTACHMENT0 }; - glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments); - - if (fbo != previousFbo) { - renderState.bindFramebuffer(previousFbo); - } - } - } -#endif -} - -bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap) { - Caches& caches = Caches::getInstance(); - if (layer && layer->isRenderable() - && bitmap->width() <= caches.maxTextureSize - && bitmap->height() <= caches.maxTextureSize) { - - GLuint fbo = renderState.createFramebuffer(); - if (!fbo) { - ALOGW("Could not obtain an FBO"); - return false; - } - - SkAutoLockPixels alp(*bitmap); - - GLuint texture; - GLuint previousFbo; - GLsizei previousViewportWidth; - GLsizei previousViewportHeight; - - GLenum format; - GLenum type; - - bool status = false; - - switch (bitmap->colorType()) { - case kAlpha_8_SkColorType: - format = GL_ALPHA; - type = GL_UNSIGNED_BYTE; - break; - case kRGB_565_SkColorType: - format = GL_RGB; - type = GL_UNSIGNED_SHORT_5_6_5; - break; - case kARGB_4444_SkColorType: - format = GL_RGBA; - type = GL_UNSIGNED_SHORT_4_4_4_4; - break; - case kN32_SkColorType: - default: - format = GL_RGBA; - type = GL_UNSIGNED_BYTE; - break; - } - - float alpha = layer->getAlpha(); - SkXfermode::Mode mode = layer->getMode(); - GLuint previousLayerFbo = layer->getFbo(); - - layer->setAlpha(255, SkXfermode::kSrc_Mode); - layer->setFbo(fbo); - - previousFbo = renderState.getFramebuffer(); - renderState.getViewport(&previousViewportWidth, &previousViewportHeight); - renderState.bindFramebuffer(fbo); - - glGenTextures(1, &texture); - - caches.textureState().activateTexture(0); - caches.textureState().bindTexture(texture); - - glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel()); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(), - 0, format, type, nullptr); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, texture, 0); - - { - LayerRenderer renderer(renderState, layer); - renderer.OpenGLRenderer::prepareDirty(bitmap->width(), bitmap->height(), - 0.0f, 0.0f, bitmap->width(), bitmap->height(), !layer->isBlend()); - - renderState.scissor().setEnabled(false); - renderer.translate(0.0f, bitmap->height()); - renderer.scale(1.0f, -1.0f); - - { - Rect bounds; - bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height()); - renderer.drawTextureLayer(layer, bounds); - - glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, - type, bitmap->getPixels()); - - } - - status = true; - } - - renderState.bindFramebuffer(previousFbo); - layer->setAlpha(alpha, mode); - layer->setFbo(previousLayerFbo); - caches.textureState().deleteTexture(texture); - renderState.deleteFramebuffer(fbo); - renderState.setViewport(previousViewportWidth, previousViewportHeight); - - GL_CHECKPOINT(MODERATE); + bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform) { + layer->setBlend(!isOpaque); + layer->setForceFilter(forceFilter); + layer->setSize(width, height); + layer->layer.set(0.0f, 0.0f, width, height); + layer->getTexTransform().load(textureTransform); - return status; + if (renderTarget != layer->getRenderTarget()) { + layer->setRenderTarget(renderTarget); + layer->bindTexture(); + layer->setFilter(GL_NEAREST, false, true); + layer->setWrap(GL_CLAMP_TO_EDGE, false, true); } - return false; } }; // namespace uirenderer diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index 38c3705cfa25..7460e3e47fa2 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -14,12 +14,10 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_LAYER_RENDERER_H -#define ANDROID_HWUI_LAYER_RENDERER_H +#pragma once #include <cutils/compiler.h> -#include "OpenGLRenderer.h" #include "Layer.h" #include <SkBitmap.h> @@ -44,41 +42,12 @@ class RenderState; // Renderer /////////////////////////////////////////////////////////////////////////////// -class LayerRenderer: public OpenGLRenderer { +class LayerRenderer { public: - LayerRenderer(RenderState& renderState, Layer* layer); - virtual ~LayerRenderer(); - - virtual void onViewportInitialized() override { /* do nothing */ } - virtual void prepareDirty(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque) override; - virtual void clear(float left, float top, float right, float bottom, bool opaque) override; - virtual bool finish() override; - static Layer* createTextureLayer(RenderState& renderState); - static Layer* createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height); - static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform); - static void destroyLayer(Layer* layer); - static bool copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap); - - static void flushLayer(RenderState& renderState, Layer* layer); - -protected: - virtual void ensureStencilBuffer() override; - virtual bool hasLayer() const override; - virtual Region* getRegion() const override; - virtual GLuint getTargetFbo() const override; - virtual bool suppressErrorChecks() const override; - -private: - void generateMesh(); - - Layer* mLayer; }; // class LayerRenderer }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_LAYER_RENDERER_H diff --git a/libs/hwui/OpDumper.cpp b/libs/hwui/OpDumper.cpp index ec9ffdeebb4c..f4b7ee0fe430 100644 --- a/libs/hwui/OpDumper.cpp +++ b/libs/hwui/OpDumper.cpp @@ -16,6 +16,7 @@ #include "OpDumper.h" +#include "ClipArea.h" #include "RecordedOp.h" namespace android { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp deleted file mode 100644 index 9d821f38fab6..000000000000 --- a/libs/hwui/OpenGLRenderer.cpp +++ /dev/null @@ -1,2451 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <GpuMemoryTracker.h> -#include "OpenGLRenderer.h" - -#include "DeferredDisplayList.h" -#include "GammaFontRenderer.h" -#include "Glop.h" -#include "GlopBuilder.h" -#include "Patch.h" -#include "PathTessellator.h" -#include "Properties.h" -#include "RenderNode.h" -#include "renderstate/MeshState.h" -#include "renderstate/RenderState.h" -#include "ShadowTessellator.h" -#include "SkiaShader.h" -#include "Vector.h" -#include "VertexBuffer.h" -#include "hwui/Canvas.h" -#include "utils/GLUtils.h" -#include "utils/PaintUtils.h" -#include "utils/TraceUtils.h" - -#include <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <SkColor.h> -#include <SkPaintDefaults.h> -#include <SkPathOps.h> -#include <SkShader.h> -#include <SkTypeface.h> - -#include <utils/Log.h> -#include <utils/StopWatch.h> - -#include <private/hwui/DrawGlInfo.h> - -#include <ui/Rect.h> - -#if DEBUG_DETAILED_EVENTS - #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__) -#else - #define EVENT_LOGD(...) -#endif - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -OpenGLRenderer::OpenGLRenderer(RenderState& renderState) - : mState(*this) - , mCaches(Caches::getInstance()) - , mRenderState(renderState) - , mFrameStarted(false) - , mScissorOptimizationDisabled(false) - , mDirty(false) - , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN}) - , mLightRadius(FLT_MIN) - , mAmbientShadowAlpha(0) - , mSpotShadowAlpha(0) { -} - -OpenGLRenderer::~OpenGLRenderer() { - // The context has already been destroyed at this point, do not call - // GL APIs. All GL state should be kept in Caches.h -} - -void OpenGLRenderer::initProperties() { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) { - mScissorOptimizationDisabled = !strcasecmp(property, "true"); - INIT_LOGD(" Scissor optimization %s", - mScissorOptimizationDisabled ? "disabled" : "enabled"); - } else { - INIT_LOGD(" Scissor optimization enabled"); - } -} - -void OpenGLRenderer::initLight(float lightRadius, uint8_t ambientShadowAlpha, - uint8_t spotShadowAlpha) { - mLightRadius = lightRadius; - mAmbientShadowAlpha = ambientShadowAlpha; - mSpotShadowAlpha = spotShadowAlpha; -} - -void OpenGLRenderer::setLightCenter(const Vector3& lightCenter) { - mLightCenter = lightCenter; -} - -/////////////////////////////////////////////////////////////////////////////// -// Setup -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::onViewportInitialized() { - glDisable(GL_DITHER); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); -} - -void OpenGLRenderer::setupFrameState(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque) { - mCaches.clearGarbage(); - mState.initializeSaveStack(viewportWidth, viewportHeight, - left, top, right, bottom, mLightCenter); - mOpaque = opaque; - mTilingClip.set(left, top, right, bottom); -} - -void OpenGLRenderer::startFrame() { - if (mFrameStarted) return; - mFrameStarted = true; - - mState.setDirtyClip(true); - - discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom); - - mRenderState.setViewport(mState.getWidth(), mState.getHeight()); - - debugOverdraw(true, true); - - clear(mTilingClip.left, mTilingClip.top, - mTilingClip.right, mTilingClip.bottom, mOpaque); -} - -void OpenGLRenderer::prepareDirty(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque) { - - setupFrameState(viewportWidth, viewportHeight, left, top, right, bottom, opaque); - - // Layer renderers will start the frame immediately - // The framebuffer renderer will first defer the display list - // for each layer and wait until the first drawing command - // to start the frame - if (currentSnapshot()->fbo == 0) { - mRenderState.blend().syncEnabled(); - updateLayers(); - } else { - startFrame(); - } -} - -void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) { - // If we know that we are going to redraw the entire framebuffer, - // perform a discard to let the driver know we don't need to preserve - // the back buffer for this frame. - if (mCaches.extensions().hasDiscardFramebuffer() && - left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) { - const bool isFbo = getTargetFbo() == 0; - const GLenum attachments[] = { - isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0, - isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT }; - glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments); - } -} - -void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { - if (!opaque) { - mRenderState.scissor().setEnabled(true); - mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top); - glClear(GL_COLOR_BUFFER_BIT); - mDirty = true; - return; - } - - mRenderState.scissor().reset(); -} - -bool OpenGLRenderer::finish() { - renderOverdraw(); - mTempPaths.clear(); - - // When finish() is invoked on FBO 0 we've reached the end - // of the current frame - if (getTargetFbo() == 0) { - mCaches.pathCache.trim(); - mCaches.tessellationCache.trim(); - } - - if (!suppressErrorChecks()) { - GL_CHECKPOINT(MODERATE); - -#if DEBUG_MEMORY_USAGE - mCaches.dumpMemoryUsage(); - GPUMemoryTracker::dump(); -#else - if (Properties::debugLevel & kDebugMemory) { - mCaches.dumpMemoryUsage(); - } -#endif - } - - mFrameStarted = false; - - return reportAndClearDirty(); -} - -void OpenGLRenderer::resumeAfterLayer() { - mRenderState.setViewport(getViewportWidth(), getViewportHeight()); - mRenderState.bindFramebuffer(currentSnapshot()->fbo); - debugOverdraw(true, false); - - mRenderState.scissor().reset(); - dirtyClip(); -} - -void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { - if (mState.currentlyIgnored()) return; - - Rect clip(mState.currentRenderTargetClip()); - clip.snapToPixelBoundaries(); - - // Since we don't know what the functor will draw, let's dirty - // the entire clip region - if (hasLayer()) { - dirtyLayerUnchecked(clip, getRegion()); - } - - DrawGlInfo info; - info.clipLeft = clip.left; - info.clipTop = clip.top; - info.clipRight = clip.right; - info.clipBottom = clip.bottom; - info.isLayer = hasLayer(); - info.width = getViewportWidth(); - info.height = getViewportHeight(); - currentTransform()->copyTo(&info.transform[0]); - - bool prevDirtyClip = mState.getDirtyClip(); - // setup GL state for functor - if (mState.getDirtyClip()) { - setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt() - } - if (mRenderState.scissor().setEnabled(true) || prevDirtyClip) { - setScissorFromClip(); - } - - mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info); - // Scissor may have been modified, reset dirty clip - dirtyClip(); - - mDirty = true; -} - -/////////////////////////////////////////////////////////////////////////////// -// Debug -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const { -#if DEBUG_DETAILED_EVENTS - const int BUFFER_SIZE = 256; - va_list ap; - char buf[BUFFER_SIZE]; - - va_start(ap, fmt); - vsnprintf(buf, BUFFER_SIZE, fmt, ap); - va_end(ap); - - eventMark(buf); -#endif -} - - -void OpenGLRenderer::eventMark(const char* name) const { - mCaches.eventMark(0, name); -} - -void OpenGLRenderer::startMark(const char* name) const { - mCaches.startMark(0, name); -} - -void OpenGLRenderer::endMark() const { - mCaches.endMark(); -} - -void OpenGLRenderer::debugOverdraw(bool enable, bool clear) { - mRenderState.debugOverdraw(enable, clear); -} - -void OpenGLRenderer::renderOverdraw() { - if (Properties::debugOverdraw && getTargetFbo() == 0) { - const Rect* clip = &mTilingClip; - - mRenderState.scissor().setEnabled(true); - mRenderState.scissor().set(clip->left, - mState.firstSnapshot()->getViewportHeight() - clip->bottom, - clip->right - clip->left, - clip->bottom - clip->top); - - // 1x overdraw - mRenderState.stencil().enableDebugTest(2); - drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode); - - // 2x overdraw - mRenderState.stencil().enableDebugTest(3); - drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode); - - // 3x overdraw - mRenderState.stencil().enableDebugTest(4); - drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode); - - // 4x overdraw and higher - mRenderState.stencil().enableDebugTest(4, true); - drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode); - - mRenderState.stencil().disable(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Layers -/////////////////////////////////////////////////////////////////////////////// - -bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { - if (layer->deferredUpdateScheduled && layer->renderer - && layer->renderNode.get() && layer->renderNode->isRenderable()) { - - if (inFrame) { - debugOverdraw(false, false); - } - - if (CC_UNLIKELY(inFrame || Properties::drawDeferDisabled)) { - layer->render(*this); - } else { - layer->defer(*this); - } - - if (inFrame) { - resumeAfterLayer(); - } - - layer->debugDrawUpdate = Properties::debugLayersUpdates; - layer->hasDrawnSinceUpdate = false; - - return true; - } - - return false; -} - -void OpenGLRenderer::updateLayers() { - // If draw deferring is enabled this method will simply defer - // the display list of each individual layer. The layers remain - // in the layer updates list which will be cleared by flushLayers(). - int count = mLayerUpdates.size(); - if (count > 0) { - if (CC_UNLIKELY(Properties::drawDeferDisabled)) { - startMark("Layer Updates"); - } else { - startMark("Defer Layer Updates"); - } - - // Note: it is very important to update the layers in order - for (int i = 0; i < count; i++) { - Layer* layer = mLayerUpdates[i].get(); - updateLayer(layer, false); - } - - if (CC_UNLIKELY(Properties::drawDeferDisabled)) { - mLayerUpdates.clear(); - mRenderState.bindFramebuffer(getTargetFbo()); - } - endMark(); - } -} - -void OpenGLRenderer::flushLayers() { - int count = mLayerUpdates.size(); - if (count > 0) { - startMark("Apply Layer Updates"); - - // Note: it is very important to update the layers in order - for (int i = 0; i < count; i++) { - mLayerUpdates[i]->flush(); - } - - mLayerUpdates.clear(); - mRenderState.bindFramebuffer(getTargetFbo()); - - endMark(); - } -} - -void OpenGLRenderer::pushLayerUpdate(Layer* layer) { - if (layer) { - // Make sure we don't introduce duplicates. - // SortedVector would do this automatically but we need to respect - // the insertion order. The linear search is not an issue since - // this list is usually very short (typically one item, at most a few) - for (int i = mLayerUpdates.size() - 1; i >= 0; i--) { - if (mLayerUpdates[i] == layer) { - return; - } - } - mLayerUpdates.push_back(layer); - } -} - -void OpenGLRenderer::cancelLayerUpdate(Layer* layer) { - if (layer) { - for (int i = mLayerUpdates.size() - 1; i >= 0; i--) { - if (mLayerUpdates[i] == layer) { - mLayerUpdates.erase(mLayerUpdates.begin() + i); - break; - } - } - } -} - -void OpenGLRenderer::flushLayerUpdates() { - ATRACE_NAME("Update HW Layers"); - mRenderState.blend().syncEnabled(); - updateLayers(); - flushLayers(); - // Wait for all the layer updates to be executed - glFinish(); -} - -void OpenGLRenderer::markLayersAsBuildLayers() { - for (size_t i = 0; i < mLayerUpdates.size(); i++) { - mLayerUpdates[i]->wasBuildLayered = true; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// State management -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { - bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer; - bool restoreClip = removed.flags & Snapshot::kFlagClipSet; - bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer; - - if (restoreViewport) { - mRenderState.setViewport(getViewportWidth(), getViewportHeight()); - } - - if (restoreClip) { - dirtyClip(); - } - - if (restoreLayer) { - endMark(); // Savelayer - ATRACE_END(); // SaveLayer - startMark("ComposeLayer"); - composeLayer(removed, restored); - endMark(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Layers -/////////////////////////////////////////////////////////////////////////////// - -int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags, const SkPath* convexMask) { - // force matrix/clip isolation for layer - flags |= SaveFlags::MatrixClip; - - const int count = mState.saveSnapshot(flags); - - if (!mState.currentlyIgnored()) { - createLayer(left, top, right, bottom, paint, flags, convexMask); - } - - return count; -} - -void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) { - const Rect untransformedBounds(bounds); - - currentTransform()->mapRect(bounds); - - // Layers only make sense if they are in the framebuffer's bounds - bounds.doIntersect(mState.currentRenderTargetClip()); - if (!bounds.isEmpty()) { - // We cannot work with sub-pixels in this case - bounds.snapToPixelBoundaries(); - - // When the layer is not an FBO, we may use glCopyTexImage so we - // need to make sure the layer does not extend outside the bounds - // of the framebuffer - const Snapshot& previous = *(currentSnapshot()->previous); - Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight()); - - bounds.doIntersect(previousViewport); - if (!bounds.isEmpty() && fboLayer) { - clip.set(bounds); - mat4 inverse; - inverse.loadInverse(*currentTransform()); - inverse.mapRect(clip); - clip.snapToPixelBoundaries(); - clip.doIntersect(untransformedBounds); - if (!clip.isEmpty()) { - clip.translate(-untransformedBounds.left, -untransformedBounds.top); - bounds.set(untransformedBounds); - } - } - } -} - -void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip, - bool fboLayer, int alpha) { - if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize || - bounds.getHeight() > mCaches.maxTextureSize || - (fboLayer && clip.isEmpty())) { - writableSnapshot()->empty = fboLayer; - } else { - writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer); - } -} - -int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom, - const SkPaint* paint, int flags) { - const int count = mState.saveSnapshot(flags); - - if (!mState.currentlyIgnored() && (flags & SaveFlags::ClipToLayer)) { - // initialize the snapshot as though it almost represents an FBO layer so deferred draw - // operations will be able to store and restore the current clip and transform info, and - // quick rejection will be correct (for display lists) - - Rect bounds(left, top, right, bottom); - Rect clip; - calculateLayerBoundsAndClip(bounds, clip, true); - updateSnapshotIgnoreForLayer(bounds, clip, true, PaintUtils::getAlphaDirect(paint)); - - if (!mState.currentlyIgnored()) { - writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f); - writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom); - writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight()); - writableSnapshot()->roundRectClipState = nullptr; - } - } - - return count; -} - -/** - * Layers are viewed by Skia are slightly different than layers in image editing - * programs (for instance.) When a layer is created, previously created layers - * and the frame buffer still receive every drawing command. For instance, if a - * layer is created and a shape intersecting the bounds of the layers and the - * framebuffer is draw, the shape will be drawn on both (unless the layer was - * created with the SaveFlags::ClipToLayer flag.) - * - * A way to implement layers is to create an FBO for each layer, backed by an RGBA - * texture. Unfortunately, this is inefficient as it requires every primitive to - * be drawn n + 1 times, where n is the number of active layers. In practice this - * means, for every primitive: - * - Switch active frame buffer - * - Change viewport, clip and projection matrix - * - Issue the drawing - * - * Switching rendering target n + 1 times per drawn primitive is extremely costly. - * To avoid this, layers are implemented in a different way here, at least in the - * general case. FBOs are used, as an optimization, when the "clip to layer" flag - * is set. When this flag is set we can redirect all drawing operations into a - * single FBO. - * - * This implementation relies on the frame buffer being at least RGBA 8888. When - * a layer is created, only a texture is created, not an FBO. The content of the - * frame buffer contained within the layer's bounds is copied into this texture - * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame - * buffer and drawing continues as normal. This technique therefore treats the - * frame buffer as a scratch buffer for the layers. - * - * To compose the layers back onto the frame buffer, each layer texture - * (containing the original frame buffer data) is drawn as a simple quad over - * the frame buffer. The trick is that the quad is set as the composition - * destination in the blending equation, and the frame buffer becomes the source - * of the composition. - * - * Drawing layers with an alpha value requires an extra step before composition. - * An empty quad is drawn over the layer's region in the frame buffer. This quad - * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the - * quad is used to multiply the colors in the frame buffer. This is achieved by - * changing the GL blend functions for the GL_FUNC_ADD blend equation to - * GL_ZERO, GL_SRC_ALPHA. - * - * Because glCopyTexImage2D() can be slow, an alternative implementation might - * be use to draw a single clipped layer. The implementation described above - * is correct in every case. - * - * (1) The frame buffer is actually not cleared right away. To allow the GPU - * to potentially optimize series of calls to glCopyTexImage2D, the frame - * buffer is left untouched until the first drawing operation. Only when - * something actually gets drawn are the layers regions cleared. - */ -bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags, const SkPath* convexMask) { - LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top); - LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); - - const bool fboLayer = flags & SaveFlags::ClipToLayer; - - // Window coordinates of the layer - Rect clip; - Rect bounds(left, top, right, bottom); - calculateLayerBoundsAndClip(bounds, clip, fboLayer); - updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, PaintUtils::getAlphaDirect(paint)); - - // Bail out if we won't draw in this snapshot - if (mState.currentlyIgnored()) { - return false; - } - - mCaches.textureState().activateTexture(0); - Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight()); - if (!layer) { - return false; - } - - layer->setPaint(paint); - layer->layer.set(bounds); - layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()), - bounds.getWidth() / float(layer->getWidth()), 0.0f); - - layer->setBlend(true); - layer->setDirty(false); - layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache - - // Save the layer in the snapshot - writableSnapshot()->flags |= Snapshot::kFlagIsLayer; - writableSnapshot()->layer = layer; - - ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u", - fboLayer ? "" : "unclipped ", - layer->getWidth(), layer->getHeight()); - startMark("SaveLayer"); - if (fboLayer) { - return createFboLayer(layer, bounds, clip); - } else { - // Copy the framebuffer into the layer - layer->bindTexture(); - if (!bounds.isEmpty()) { - if (layer->isEmpty()) { - // Workaround for some GL drivers. When reading pixels lying outside - // of the window we should get undefined values for those pixels. - // Unfortunately some drivers will turn the entire target texture black - // when reading outside of the window. - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(), - 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - layer->setEmpty(false); - } - - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, - bounds.left, getViewportHeight() - bounds.bottom, - bounds.getWidth(), bounds.getHeight()); - - // Enqueue the buffer coordinates to clear the corresponding region later - mLayers.push_back(Rect(bounds)); - } - } - - return true; -} - -bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) { - layer->clipRect.set(clip); - layer->setFbo(mRenderState.createFramebuffer()); - - writableSnapshot()->region = &writableSnapshot()->layer->region; - writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer; - writableSnapshot()->fbo = layer->getFbo(); - writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f); - writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom); - writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight()); - writableSnapshot()->roundRectClipState = nullptr; - - debugOverdraw(false, false); - // Bind texture to FBO - mRenderState.bindFramebuffer(layer->getFbo()); - layer->bindTexture(); - - // Initialize the texture if needed - if (layer->isEmpty()) { - layer->allocateTexture(); - layer->setEmpty(false); - } - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - layer->getTextureId(), 0); - - // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering - mRenderState.scissor().setEnabled(true); - mRenderState.scissor().set(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f, - clip.getWidth() + 2.0f, clip.getHeight() + 2.0f); - glClear(GL_COLOR_BUFFER_BIT); - - dirtyClip(); - - // Change the ortho projection - mRenderState.setViewport(bounds.getWidth(), bounds.getHeight()); - return true; -} - -/** - * Read the documentation of createLayer() before doing anything in this method. - */ -void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) { - if (!removed.layer) { - ALOGE("Attempting to compose a layer that does not exist"); - return; - } - - Layer* layer = removed.layer; - const Rect& rect = layer->layer; - const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer; - - bool clipRequired = false; - mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom, - &clipRequired, nullptr, false); // safely ignore return, should never be rejected - mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); - - if (fboLayer) { - // Detach the texture from the FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - - layer->removeFbo(false); - - // Unbind current FBO and restore previous one - mRenderState.bindFramebuffer(restored.fbo); - debugOverdraw(true, false); - } - - if (!fboLayer && layer->getAlpha() < 255) { - SkPaint layerPaint; - layerPaint.setAlpha(layer->getAlpha()); - layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode); - layerPaint.setColorFilter(layer->getColorFilter()); - - drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true); - // Required below, composeLayerRect() will divide by 255 - layer->setAlpha(255); - } - - mRenderState.meshState().unbindMeshBuffer(); - - mCaches.textureState().activateTexture(0); - - // When the layer is stored in an FBO, we can save a bit of fillrate by - // drawing only the dirty region - if (fboLayer) { - dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform); - composeLayerRegion(layer, rect); - } else if (!rect.isEmpty()) { - dirtyLayer(rect.left, rect.top, rect.right, rect.bottom); - - save(0); - // the layer contains screen buffer content that shouldn't be alpha modulated - // (and any necessary alpha modulation was handled drawing into the layer) - writableSnapshot()->alpha = 1.0f; - composeLayerRectSwapped(layer, rect); - restore(); - } - - dirtyClip(); - - // Failing to add the layer to the cache should happen only if the layer is too large - layer->setConvexMask(nullptr); - if (!mCaches.layerCache.put(layer)) { - LAYER_LOGD("Deleting layer"); - layer->decStrong(nullptr); - } -} - -void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { - const bool tryToSnap = !layer->getForceFilter() - && layer->getWidth() == (uint32_t) rect.getWidth() - && layer->getHeight() == (uint32_t) rect.getHeight(); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO - .setFillTextureLayer(*layer, getLayerAlpha(layer)) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::composeLayerRectSwapped(Layer* layer, const Rect& rect) { - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUvQuad(nullptr, layer->texCoords) - .setFillLayer(layer->getTexture(), layer->getColorFilter(), - getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::Swap) - .setTransform(*currentSnapshot(), TransformFlags::MeshIgnoresCanvasTransform) - .setModelViewMapUnitToRect(rect) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect) { - if (layer->isTextureLayer()) { - EVENT_LOGD("composeTextureLayerRect"); - drawTextureLayer(layer, rect); - } else { - EVENT_LOGD("composeHardwareLayerRect"); - - const bool tryToSnap = layer->getWidth() == static_cast<uint32_t>(rect.getWidth()) - && layer->getHeight() == static_cast<uint32_t>(rect.getHeight()); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUvQuad(nullptr, layer->texCoords) - .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect) - .build(); - renderGlop(glop); - } -} - -/** - * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated - * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw - * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used - * by saveLayer's restore - */ -#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \ - DRAW_COMMAND; \ - if (CC_UNLIKELY(Properties::debugOverdraw && getTargetFbo() == 0 && (COND))) { \ - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \ - DRAW_COMMAND; \ - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \ - } \ - } - -#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND) - -// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to -// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque. -class LayerShader : public SkShader { -public: - LayerShader(Layer* layer, const SkMatrix* localMatrix) - : INHERITED(localMatrix) - , mLayer(layer) { - } - - virtual bool asACustomShader(void** data) const override { - if (data) { - *data = static_cast<void*>(mLayer); - } - return true; - } - - virtual bool isOpaque() const override { - return !mLayer->isBlend(); - } - -protected: - virtual void shadeSpan(int x, int y, SkPMColor[], int count) { - LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend."); - } - - virtual void flatten(SkWriteBuffer&) const override { - LOG_ALWAYS_FATAL("LayerShader should never be flattened."); - } - - virtual Factory getFactory() const override { - LOG_ALWAYS_FATAL("LayerShader should never be created from a stream."); - return nullptr; - } -private: - // Unowned. - Layer* mLayer; - typedef SkShader INHERITED; -}; - -void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { - if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw - - if (layer->getConvexMask()) { - save(SaveFlags::MatrixClip); - - // clip to the area of the layer the mask can be larger - clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op); - - SkPaint paint; - paint.setAntiAlias(true); - paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0)); - - // create LayerShader to map SaveLayer content into subsequent draw - SkMatrix shaderMatrix; - shaderMatrix.setTranslate(rect.left, rect.bottom); - shaderMatrix.preScale(1, -1); - LayerShader layerShader(layer, &shaderMatrix); - paint.setShader(&layerShader); - - // Since the drawing primitive is defined in local drawing space, - // we don't need to modify the draw matrix - const SkPath* maskPath = layer->getConvexMask(); - DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint)); - - paint.setShader(nullptr); - restore(); - - return; - } - - if (layer->region.isRect()) { - layer->setRegionAsRect(); - - DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect)); - - layer->region.clear(); - return; - } - - EVENT_LOGD("composeLayerRegion"); - // standard Region based draw - size_t count; - const android::Rect* rects; - Region safeRegion; - if (CC_LIKELY(hasRectToRectTransform())) { - rects = layer->region.getArray(&count); - } else { - safeRegion = Region::createTJunctionFreeRegion(layer->region); - rects = safeRegion.getArray(&count); - } - - const float texX = 1.0f / float(layer->getWidth()); - const float texY = 1.0f / float(layer->getHeight()); - const float height = rect.getHeight(); - - TextureVertex quadVertices[count * 4]; - TextureVertex* mesh = &quadVertices[0]; - for (size_t i = 0; i < count; i++) { - const android::Rect* r = &rects[i]; - - const float u1 = r->left * texX; - const float v1 = (height - r->top) * texY; - const float u2 = r->right * texX; - const float v2 = (height - r->bottom) * texY; - - // TODO: Reject quads outside of the clip - TextureVertex::set(mesh++, r->left, r->top, u1, v1); - TextureVertex::set(mesh++, r->right, r->top, u2, v1); - TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); - TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); - } - Rect modelRect = Rect(rect.getWidth(), rect.getHeight()); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6) - .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewOffsetRectSnap(rect.left, rect.top, modelRect) - .build(); - DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop)); - -#if DEBUG_LAYERS_AS_REGIONS - drawRegionRectsDebug(layer->region); -#endif - - layer->region.clear(); -} - -#if DEBUG_LAYERS_AS_REGIONS -void OpenGLRenderer::drawRegionRectsDebug(const Region& region) { - size_t count; - const android::Rect* rects = region.getArray(&count); - - uint32_t colors[] = { - 0x7fff0000, 0x7f00ff00, - 0x7f0000ff, 0x7fff00ff, - }; - - int offset = 0; - int32_t top = rects[0].top; - - for (size_t i = 0; i < count; i++) { - if (top != rects[i].top) { - offset ^= 0x2; - top = rects[i].top; - } - - SkPaint paint; - paint.setColor(colors[offset + (i & 0x1)]); - Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom); - drawColorRect(r.left, r.top, r.right, r.bottom, paint); - } -} -#endif - -void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) { - Vector<float> rects; - - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - rects.push(r.fLeft); - rects.push(r.fTop); - rects.push(r.fRight); - rects.push(r.fBottom); - it.next(); - } - - drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false); -} - -void OpenGLRenderer::dirtyLayer(const float left, const float top, - const float right, const float bottom, const Matrix4& transform) { - if (hasLayer()) { - Rect bounds(left, top, right, bottom); - transform.mapRect(bounds); - dirtyLayerUnchecked(bounds, getRegion()); - } -} - -void OpenGLRenderer::dirtyLayer(const float left, const float top, - const float right, const float bottom) { - if (hasLayer()) { - Rect bounds(left, top, right, bottom); - dirtyLayerUnchecked(bounds, getRegion()); - } -} - -void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { - bounds.doIntersect(mState.currentRenderTargetClip()); - if (!bounds.isEmpty()) { - bounds.snapToPixelBoundaries(); - android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); - if (!dirty.isEmpty()) { - region->orSelf(dirty); - } - } -} - -void OpenGLRenderer::clearLayerRegions() { - const size_t quadCount = mLayers.size(); - if (quadCount == 0) return; - - if (!mState.currentlyIgnored()) { - EVENT_LOGD("clearLayerRegions"); - // Doing several glScissor/glClear here can negatively impact - // GPUs with a tiler architecture, instead we draw quads with - // the Clear blending mode - - // The list contains bounds that have already been clipped - // against their initial clip rect, and the current clip - // is likely different so we need to disable clipping here - bool scissorChanged = mRenderState.scissor().setEnabled(false); - - Vertex mesh[quadCount * 4]; - Vertex* vertex = mesh; - - for (uint32_t i = 0; i < quadCount; i++) { - const Rect& bounds = mLayers[i]; - - Vertex::set(vertex++, bounds.left, bounds.top); - Vertex::set(vertex++, bounds.right, bounds.top); - Vertex::set(vertex++, bounds.left, bounds.bottom); - Vertex::set(vertex++, bounds.right, bounds.bottom); - } - // We must clear the list of dirty rects before we - // call clearLayerRegions() in renderGlop to prevent - // stencil setup from doing the same thing again - mLayers.clear(); - - const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(nullptr) // clear ignores clip state - .setMeshIndexedQuads(&mesh[0], quadCount) - .setFillClear() - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getRenderTargetClip())) - .build(); - renderGlop(glop, GlopRenderType::LayerClear); - - if (scissorChanged) mRenderState.scissor().setEnabled(true); - } else { - mLayers.clear(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// State Deferral -/////////////////////////////////////////////////////////////////////////////// - -bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) { - const Rect& currentClip = mState.currentRenderTargetClip(); - const mat4* currentMatrix = currentTransform(); - - if (stateDeferFlags & kStateDeferFlag_Draw) { - // state has bounds initialized in local coordinates - if (!state.mBounds.isEmpty()) { - currentMatrix->mapRect(state.mBounds); - Rect clippedBounds(state.mBounds); - // NOTE: if we ever want to use this clipping info to drive whether the scissor - // is used, it should more closely duplicate the quickReject logic (in how it uses - // snapToPixelBoundaries) - - clippedBounds.doIntersect(currentClip); - if (clippedBounds.isEmpty()) { - // quick rejected - return true; - } - - state.mClipSideFlags = kClipSide_None; - if (!currentClip.contains(state.mBounds)) { - int& flags = state.mClipSideFlags; - // op partially clipped, so record which sides are clipped for clip-aware merging - if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left; - if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top; - if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right; - if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom; - } - state.mBounds.set(clippedBounds); - } else { - // Empty bounds implies size unknown. Label op as conservatively clipped to disable - // overdraw avoidance (since we don't know what it overlaps) - state.mClipSideFlags = kClipSide_ConservativeFull; - state.mBounds.set(currentClip); - } - } - - state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip); - if (state.mClipValid) { - state.mClip.set(currentClip); - } - - // Transform and alpha always deferred, since they are used by state operations - // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything) - state.mMatrix = *currentMatrix; - state.mAlpha = currentSnapshot()->alpha; - - // always store/restore, since these are just pointers - state.mRoundRectClipState = currentSnapshot()->roundRectClipState; -#if !HWUI_NEW_OPS - state.mProjectionPathMask = currentSnapshot()->projectionPathMask; -#endif - return false; -} - -void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) { - setGlobalMatrix(state.mMatrix); - writableSnapshot()->alpha = state.mAlpha; - writableSnapshot()->roundRectClipState = state.mRoundRectClipState; -#if !HWUI_NEW_OPS - writableSnapshot()->projectionPathMask = state.mProjectionPathMask; -#endif - - if (state.mClipValid && !skipClipRestore) { - writableSnapshot()->setClip(state.mClip.left, state.mClip.top, - state.mClip.right, state.mClip.bottom); - dirtyClip(); - } -} - -/** - * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done - * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at - * least one op is clipped), or disabled entirely (because no merged op is clipped) - * - * This method should be called when restoreDisplayState() won't be restoring the clip - */ -void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) { - if (clipRect != nullptr) { - writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); - } else { - writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight()); - } - dirtyClip(); - bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled; - mRenderState.scissor().setEnabled(enableScissor); -} - -/////////////////////////////////////////////////////////////////////////////// -// Clipping -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::setScissorFromClip() { - Rect clip(mState.currentRenderTargetClip()); - clip.snapToPixelBoundaries(); - - if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom, - clip.getWidth(), clip.getHeight())) { - mState.setDirtyClip(false); - } -} - -void OpenGLRenderer::ensureStencilBuffer() { - // Thanks to the mismatch between EGL and OpenGL ES FBO we - // cannot attach a stencil buffer to fbo0 dynamically. Let's - // just hope we have one when hasLayer() returns false. - if (hasLayer()) { - attachStencilBufferToLayer(currentSnapshot()->layer); - } -} - -void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) { - // The layer's FBO is already bound when we reach this stage - if (!layer->getStencilRenderBuffer()) { - RenderBuffer* buffer = mCaches.renderBufferCache.get( - Stencil::getLayerStencilFormat(), - layer->getWidth(), layer->getHeight()); - layer->setStencilRenderBuffer(buffer); - } -} - -static void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform, - float x, float y) { - Vertex v; - v.x = x; - v.y = y; - transform.mapPoint(v.x, v.y); - rectangleVertices.push_back(v); -} - -static void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) { - Vertex v; - v.x = x; - v.y = y; - rectangleVertices.push_back(v); -} - -void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) { - int quadCount = rectangleList.getTransformedRectanglesCount(); - std::vector<Vertex> rectangleVertices(quadCount * 4); - Rect scissorBox = rectangleList.calculateBounds(); - scissorBox.snapToPixelBoundaries(); - for (int i = 0; i < quadCount; ++i) { - const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i)); - const Matrix4& transform = tr.getTransform(); - Rect bounds = tr.getBounds(); - if (transform.rectToRect()) { - transform.mapRect(bounds); - bounds.doIntersect(scissorBox); - if (!bounds.isEmpty()) { - handlePointNoTransform(rectangleVertices, bounds.left, bounds.top); - handlePointNoTransform(rectangleVertices, bounds.right, bounds.top); - handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom); - handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom); - } - } else { - handlePoint(rectangleVertices, transform, bounds.left, bounds.top); - handlePoint(rectangleVertices, transform, bounds.right, bounds.top); - handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom); - handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom); - } - } - - mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom, - scissorBox.getWidth(), scissorBox.getHeight()); - const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform; - Glop glop; - Vertex* vertices = &rectangleVertices[0]; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshIndexedQuads(vertices, rectangleVertices.size() / 4) - .setFillBlack() - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(0, 0, scissorBox) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::setStencilFromClip() { - if (!Properties::debugOverdraw) { - if (!currentSnapshot()->clipIsSimple()) { - int incrementThreshold; - EVENT_LOGD("setStencilFromClip - enabling"); - - // NOTE: The order here is important, we must set dirtyClip to false - // before any draw call to avoid calling back into this method - mState.setDirtyClip(false); - - ensureStencilBuffer(); - - const ClipArea& clipArea = currentSnapshot()->getClipArea(); - - bool isRectangleList = clipArea.isRectangleList(); - if (isRectangleList) { - incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount(); - } else { - incrementThreshold = 0; - } - - mRenderState.stencil().enableWrite(incrementThreshold); - - // Clean and update the stencil, but first make sure we restrict drawing - // to the region's bounds - bool resetScissor = mRenderState.scissor().setEnabled(true); - if (resetScissor) { - // The scissor was not set so we now need to update it - setScissorFromClip(); - } - - mRenderState.stencil().clear(); - - // stash and disable the outline clip state, since stencil doesn't account for outline - bool storedSkipOutlineClip = mSkipOutlineClip; - mSkipOutlineClip = true; - - SkPaint paint; - paint.setColor(SK_ColorBLACK); - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - - if (isRectangleList) { - drawRectangleList(clipArea.getRectangleList()); - } else { - // NOTE: We could use the region contour path to generate a smaller mesh - // Since we are using the stencil we could use the red book path - // drawing technique. It might increase bandwidth usage though. - - // The last parameter is important: we are not drawing in the color buffer - // so we don't want to dirty the current layer, if any - drawRegionRects(clipArea.getClipRegion(), paint, false); - } - if (resetScissor) mRenderState.scissor().setEnabled(false); - mSkipOutlineClip = storedSkipOutlineClip; - - mRenderState.stencil().enableTest(incrementThreshold); - - // Draw the region used to generate the stencil if the appropriate debug - // mode is enabled - // TODO: Implement for rectangle list clip areas - if (Properties::debugStencilClip == StencilClipDebug::ShowRegion - && !clipArea.isRectangleList()) { - paint.setColor(0x7f0000ff); - paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); - drawRegionRects(currentSnapshot()->getClipRegion(), paint); - } - } else { - EVENT_LOGD("setStencilFromClip - disabling"); - mRenderState.stencil().disable(); - } - } -} - -/** - * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out. - * - * @param paint if not null, the bounds will be expanded to account for stroke depending on paint - * style, and tessellated AA ramp - */ -bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom, - const SkPaint* paint) { - bool snapOut = paint && paint->isAntiAlias(); - - if (paint && paint->getStyle() != SkPaint::kFill_Style) { - float outset = paint->getStrokeWidth() * 0.5f; - left -= outset; - top -= outset; - right += outset; - bottom += outset; - } - - bool clipRequired = false; - bool roundRectClipRequired = false; - if (mState.calculateQuickRejectForScissor(left, top, right, bottom, - &clipRequired, &roundRectClipRequired, snapOut)) { - return true; - } - - // not quick rejected, so enable the scissor if clipRequired - mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); - mSkipOutlineClip = !roundRectClipRequired; - return false; -} - -void OpenGLRenderer::debugClip() { -#if DEBUG_CLIP_REGIONS - if (!currentSnapshot()->clipRegion->isEmpty()) { - SkPaint paint; - paint.setColor(0x7f00ff00); - drawRegionRects(*(currentSnapshot()->clipRegion, paint); - - } -#endif -} - -void OpenGLRenderer::renderGlop(const Glop& glop, GlopRenderType type) { - // TODO: It would be best if we could do this before quickRejectSetupScissor() - // changes the scissor test state - if (type != GlopRenderType::LayerClear) { - // Regular draws need to clear the dirty area on the layer before they start drawing on top - // of it. If this draw *is* a layer clear, it skips the clear step (since it would - // infinitely recurse) - clearLayerRegions(); - } - - if (mState.getDirtyClip()) { - if (mRenderState.scissor().isEnabled()) { - setScissorFromClip(); - } - - setStencilFromClip(); - } - mRenderState.render(glop, currentSnapshot()->getOrthoMatrix()); - if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) { - // TODO: specify more clearly when a draw should dirty the layer. - // is writing to the stencil the only time we should ignore this? -#if !HWUI_NEW_OPS - dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom); -#endif - mDirty = true; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Drawing -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) { - // All the usual checks and setup operations (quickReject, setupDraw, etc.) - // will be performed by the display list itself - if (renderNode && renderNode->isRenderable()) { - // compute 3d ordering - renderNode->computeOrdering(); - if (CC_UNLIKELY(Properties::drawDeferDisabled)) { - startFrame(); - ReplayStateStruct replayStruct(*this, dirty, replayFlags); - renderNode->replay(replayStruct, 0); - return; - } - - DeferredDisplayList deferredList(mState.currentRenderTargetClip()); - DeferStateStruct deferStruct(deferredList, *this, replayFlags); - renderNode->defer(deferStruct, 0); - - flushLayers(); - startFrame(); - - deferredList.flush(*this, dirty); - } else { - // Even if there is no drawing command(Ex: invisible), - // it still needs startFrame to clear buffer and start tiling. - startFrame(); - } -} - -/** - * Important note: this method is intended to draw batches of bitmaps and - * will not set the scissor enable or dirty the current layer, if any. - * The caller is responsible for properly dirtying the current layer. - */ -void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, - int bitmapCount, TextureVertex* vertices, bool pureTranslate, - const Rect& bounds, const SkPaint* paint) { - Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return; - - const AutoTexture autoCleanup(texture); - - // TODO: remove layer dirty in multi-draw callers - // TODO: snap doesn't need to touch transform, only texture filter. - bool snap = pureTranslate; - const float x = floorf(bounds.left + 0.5f); - const float y = floorf(bounds.top + 0.5f); - - const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) - ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; - const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedMesh(vertices, bitmapCount * 6) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(bounds.getWidth(), bounds.getHeight())) - .build(); - renderGlop(glop, GlopRenderType::Multi); -} - -void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { - if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) { - return; - } - - mCaches.textureState().activateTexture(0); - Texture* texture = getTexture(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) - ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUnitQuad(texture->uvMapper) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height())) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint) { - if (!vertices || mState.currentlyIgnored()) { - return; - } - - float left = FLT_MAX; - float top = FLT_MAX; - float right = FLT_MIN; - float bottom = FLT_MIN; - - const uint32_t elementCount = meshWidth * meshHeight * 6; - - std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]); - ColorTextureVertex* vertex = &mesh[0]; - - std::unique_ptr<int[]> tempColors; - if (!colors) { - uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1); - tempColors.reset(new int[colorsCount]); - memset(tempColors.get(), 0xff, colorsCount * sizeof(int)); - colors = tempColors.get(); - } - - Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef()); - const UvMapper& mapper(getMapper(texture)); - - for (int32_t y = 0; y < meshHeight; y++) { - for (int32_t x = 0; x < meshWidth; x++) { - uint32_t i = (y * (meshWidth + 1) + x) * 2; - - float u1 = float(x) / meshWidth; - float u2 = float(x + 1) / meshWidth; - float v1 = float(y) / meshHeight; - float v2 = float(y + 1) / meshHeight; - - mapper.map(u1, v1, u2, v2); - - int ax = i + (meshWidth + 1) * 2; - int ay = ax + 1; - int bx = i; - int by = bx + 1; - int cx = i + 2; - int cy = cx + 1; - int dx = i + (meshWidth + 1) * 2 + 2; - int dy = dx + 1; - - ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); - ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]); - ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); - - ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); - ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); - ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]); - - left = std::min(left, std::min(vertices[ax], std::min(vertices[bx], vertices[cx]))); - top = std::min(top, std::min(vertices[ay], std::min(vertices[by], vertices[cy]))); - right = std::max(right, std::max(vertices[ax], std::max(vertices[bx], vertices[cx]))); - bottom = std::max(bottom, std::max(vertices[ay], std::max(vertices[by], vertices[cy]))); - } - } - - if (quickRejectSetupScissor(left, top, right, bottom)) { - return; - } - - if (!texture) { - texture = mCaches.textureCache.get(bitmap); - if (!texture) { - return; - } - } - const AutoTexture autoCleanup(texture); - - /* - * TODO: handle alpha_8 textures correctly by applying paint color, but *not* - * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh. - */ - const int textureFillFlags = TextureFillFlags::None; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshColoredTexturedMesh(mesh.get(), elementCount) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom)) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) { - if (quickRejectSetupScissor(dst)) { - return; - } - - Texture* texture = getTexture(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - Rect uv(std::max(0.0f, src.left / texture->width()), - std::max(0.0f, src.top / texture->height()), - std::min(1.0f, src.right / texture->width()), - std::min(1.0f, src.bottom / texture->height())); - - const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) - ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; - const bool tryToSnap = MathUtils::areEqual(src.getWidth(), dst.getWidth()) - && MathUtils::areEqual(src.getHeight(), dst.getHeight()); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUvQuad(texture->uvMapper, uv) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectOptionalSnap(tryToSnap, dst) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, - AssetAtlas::Entry* entry, float left, float top, float right, float bottom, - const SkPaint* paint) { - if (!mesh || !mesh->verticesCount || quickRejectSetupScissor(left, top, right, bottom)) { - return; - } - - Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - // 9 patches are built for stretching - always filter - int textureFillFlags = TextureFillFlags::ForceFilter; - if (bitmap->colorType() == kAlpha_8_SkColorType) { - textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture; - } - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshPatchQuads(*mesh) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewOffsetRectSnap(left, top, Rect(right - left, bottom - top)) // TODO: get minimal bounds from patch - .build(); - renderGlop(glop); -} - -/** - * Important note: this method is intended to draw batches of 9-patch objects and - * will not set the scissor enable or dirty the current layer, if any. - * The caller is responsible for properly dirtying the current layer. - */ -void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry, - TextureVertex* vertices, uint32_t elementCount, const SkPaint* paint) { - mCaches.textureState().activateTexture(0); - Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - // TODO: get correct bounds from caller - const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform; - // 9 patches are built for stretching - always filter - int textureFillFlags = TextureFillFlags::ForceFilter; - if (bitmap->colorType() == kAlpha_8_SkColorType) { - textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture; - } - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedIndexedQuads(vertices, elementCount) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(0, 0, Rect()) - .build(); - renderGlop(glop, GlopRenderType::Multi); -} - -void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, - const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) { - // not missing call to quickReject/dirtyLayer, always done at a higher level - if (!vertexBuffer.getVertexCount()) { - // no vertices to draw - return; - } - - bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp; - const int transformFlags = TransformFlags::OffsetByFudgeFactor; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshVertexBuffer(vertexBuffer) - .setFillPaint(*paint, currentSnapshot()->alpha, shadowInterp) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds()) - .build(); - renderGlop(glop); -} - -/** - * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to - * that of AA lines in the drawLines() function. We expand the convex path by a half pixel in - * screen space in all directions. However, instead of using a fragment shader to compute the - * translucency of the color from its position, we simply use a varying parameter to define how far - * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used. - * - * Doesn't yet support joins, caps, or path effects. - */ -void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) { - VertexBuffer vertexBuffer; - // TODO: try clipping large paths to viewport - - PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer); - drawVertexBuffer(vertexBuffer, paint); -} - -/** - * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha - * and additional geometry for defining an alpha slope perimeter. - * - * Using GL_LINES can be difficult because the rasterization rules for those lines produces some - * unexpected results, and may vary between hardware devices. Previously we used a varying-base - * in-shader alpha region, but found it to be taxing on some GPUs. - * - * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce - * memory transfer by removing need for degenerate vertices. - */ -void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) { - if (mState.currentlyIgnored() || count < 4) return; - - count &= ~0x3; // round down to nearest four - - VertexBuffer buffer; - PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer); - const Rect& bounds = buffer.getBounds(); - - if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) { - return; - } - - int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset; - drawVertexBuffer(buffer, paint, displayFlags); -} - -void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) { - if (mState.currentlyIgnored() || count < 2) return; - - count &= ~0x1; // round down to nearest two - - VertexBuffer buffer; - PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer); - - const Rect& bounds = buffer.getBounds(); - if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) { - return; - } - - int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset; - drawVertexBuffer(buffer, paint, displayFlags); - - mDirty = true; -} - -void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { - // No need to check against the clip, we fill the clip region - if (mState.currentlyIgnored()) return; - - Rect clip(mState.currentRenderTargetClip()); - clip.snapToPixelBoundaries(); - - SkPaint paint; - paint.setColor(color); - paint.setXfermodeMode(mode); - - drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true); - - mDirty = true; -} - -void OpenGLRenderer::drawShape(float left, float top, PathTexture* texture, - const SkPaint* paint) { - if (!texture) return; - const AutoTexture autoCleanup(texture); - - const float x = left + texture->left - texture->offset; - const float y = top + texture->top - texture->offset; - - drawPathTexture(texture, x, y, paint); - - mDirty = true; -} - -void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(left, top, right, bottom, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - if (p->getPathEffect() != nullptr) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = mCaches.pathCache.getRoundRect( - right - left, bottom - top, rx, ry, p); - drawShape(left, top, texture, p); - } else { - const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect( - *currentTransform(), *p, right - left, bottom - top, rx, ry); - drawVertexBuffer(left, top, *vertexBuffer, p); - } -} - -void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - if (p->getPathEffect() != nullptr) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = mCaches.pathCache.getCircle(radius, p); - drawShape(x - radius, y - radius, texture, p); - return; - } - - SkPath path; - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - path.addCircle(x, y, radius + p->getStrokeWidth() / 2); - } else { - path.addCircle(x, y, radius); - } - -#if !HWUI_NEW_OPS - if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) { - // mask ripples with projection mask - SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask); - - Matrix4 screenSpaceTransform; - currentSnapshot()->buildScreenSpaceTransform(&screenSpaceTransform); - - Matrix4 totalTransform; - totalTransform.loadInverse(screenSpaceTransform); - totalTransform.multiply(currentSnapshot()->projectionPathMask->projectionMaskTransform); - - SkMatrix skTotalTransform; - totalTransform.copyTo(skTotalTransform); - maskPath.transform(skTotalTransform); - - // Mask the ripple path by the projection mask, now that it's - // in local space. Note that this can create CCW paths. - Op(path, maskPath, kIntersect_SkPathOp, &path); - } -#endif - drawConvexPath(path, p); -} - -void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, - const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(left, top, right, bottom, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - if (p->getPathEffect() != nullptr) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p); - drawShape(left, top, texture, p); - } else { - SkPath path; - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); - } - path.addOval(rect); - drawConvexPath(path, p); - } -} - -void OpenGLRenderer::drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(left, top, right, bottom, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) - if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top, - startAngle, sweepAngle, useCenter, p); - drawShape(left, top, texture, p); - return; - } - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); - } - - SkPath path; - if (useCenter) { - path.moveTo(rect.centerX(), rect.centerY()); - } - path.arcTo(rect, startAngle, sweepAngle, !useCenter); - if (useCenter) { - path.close(); - } - drawConvexPath(path, p); -} - -void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, - const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(left, top, right, bottom, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - if (p->getStyle() != SkPaint::kFill_Style) { - // only fill style is supported by drawConvexPath, since others have to handle joins - static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed"); - if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join || - p->getStrokeMiter() != SkPaintDefaults_MiterLimit) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = - mCaches.pathCache.getRect(right - left, bottom - top, p); - drawShape(left, top, texture, p); - } else { - SkPath path; - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); - } - path.addRect(rect); - drawConvexPath(path, p); - } - } else { - if (p->isAntiAlias() && !currentTransform()->isSimple()) { - SkPath path; - path.addRect(left, top, right, bottom); - drawConvexPath(path, p); - } else { - drawColorRect(left, top, right, bottom, p); - - mDirty = true; - } - } -} - -void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const glyph_t* glyphs, - int count, const float* positions, - FontRenderer& fontRenderer, int alpha, float x, float y) { - mCaches.textureState().activateTexture(0); - - PaintUtils::TextShadow textShadow; - if (!PaintUtils::getTextShadow(paint, &textShadow)) { - LOG_ALWAYS_FATAL("failed to query shadow attributes"); - } - - // NOTE: The drop shadow will not perform gamma correction - // if shader-based correction is enabled - mCaches.dropShadowCache.setFontRenderer(fontRenderer); - ShadowTexture* texture = mCaches.dropShadowCache.get( - paint, glyphs, count, textShadow.radius, positions); - // If the drop shadow exceeds the max texture size or couldn't be - // allocated, skip drawing - if (!texture) return; - const AutoTexture autoCleanup(texture); - - const float sx = x - texture->left + textShadow.dx; - const float sy = y - texture->top + textShadow.dy; - - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUnitQuad(nullptr) - .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height())) - .build(); - renderGlop(glop); -} - -// TODO: remove this, once mState.currentlyIgnored captures snapshot alpha -bool OpenGLRenderer::canSkipText(const SkPaint* paint) const { - float alpha = (PaintUtils::hasTextShadow(paint) - ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha; - return MathUtils::isZero(alpha) - && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode; -} - -bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const { - if (CC_LIKELY(transform.isPureTranslate())) { - outMatrix->setIdentity(); - return false; - } else if (CC_UNLIKELY(transform.isPerspective())) { - outMatrix->setIdentity(); - return true; - } - - /** - * Input is a non-perspective, scaling transform. Generate a scale-only transform, - * with values rounded to the nearest int. - */ - float sx, sy; - transform.decomposeScale(sx, sy); - outMatrix->setScale( - roundf(std::max(1.0f, sx)), - roundf(std::max(1.0f, sy))); - return true; -} - -int OpenGLRenderer::getSaveCount() const { - return mState.getSaveCount(); -} - -int OpenGLRenderer::save(int flags) { - return mState.save(flags); -} - -void OpenGLRenderer::restore() { - mState.restore(); -} - -void OpenGLRenderer::restoreToCount(int saveCount) { - mState.restoreToCount(saveCount); -} - - -void OpenGLRenderer::translate(float dx, float dy, float dz) { - mState.translate(dx, dy, dz); -} - -void OpenGLRenderer::rotate(float degrees) { - mState.rotate(degrees); -} - -void OpenGLRenderer::scale(float sx, float sy) { - mState.scale(sx, sy); -} - -void OpenGLRenderer::skew(float sx, float sy) { - mState.skew(sx, sy); -} - -void OpenGLRenderer::setLocalMatrix(const Matrix4& matrix) { - mState.setMatrix(mBaseTransform); - mState.concatMatrix(matrix); -} - -void OpenGLRenderer::setLocalMatrix(const SkMatrix& matrix) { - mState.setMatrix(mBaseTransform); - mState.concatMatrix(matrix); -} - -void OpenGLRenderer::concatMatrix(const Matrix4& matrix) { - mState.concatMatrix(matrix); -} - -bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { - return mState.clipRect(left, top, right, bottom, op); -} - -bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) { - return mState.clipPath(path, op); -} - -bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { - return mState.clipRegion(region, op); -} - -void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) { - mState.setClippingOutline(allocator, outline); -} - -void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius, bool highPriority) { - mState.setClippingRoundRect(allocator, rect, radius, highPriority); -} - -void OpenGLRenderer::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) { - mState.setProjectionPathMask(allocator, path); -} - -void OpenGLRenderer::drawText(const glyph_t* glyphs, int bytesCount, int count, float x, float y, - const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds, - DrawOpMode drawOpMode) { - - if (drawOpMode == DrawOpMode::kImmediate) { - // The checks for corner-case ignorable text and quick rejection is only done for immediate - // drawing as ops from DeferredDisplayList are already filtered for these - if (glyphs == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) || - quickRejectSetupScissor(bounds)) { - return; - } - } - - const float oldX = x; - const float oldY = y; - - const mat4& transform = *currentTransform(); - const bool pureTranslate = transform.isPureTranslate(); - - if (CC_LIKELY(pureTranslate)) { - x = floorf(x + transform.getTranslateX() + 0.5f); - y = floorf(y + transform.getTranslateY() + 0.5f); - } - - int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha; - SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint); - - FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); - - if (CC_UNLIKELY(PaintUtils::hasTextShadow(paint))) { - fontRenderer.setFont(paint, SkMatrix::I()); - drawTextShadow(paint, glyphs, count, positions, fontRenderer, - alpha, oldX, oldY); - } - - const bool hasActiveLayer = hasLayer(); - - // We only pass a partial transform to the font renderer. That partial - // matrix defines how glyphs are rasterized. Typically we want glyphs - // to be rasterized at their final size on screen, which means the partial - // matrix needs to take the scale factor into account. - // When a partial matrix is used to transform glyphs during rasterization, - // the mesh is generated with the inverse transform (in the case of scale, - // the mesh is generated at 1.0 / scale for instance.) This allows us to - // apply the full transform matrix at draw time in the vertex shader. - // Applying the full matrix in the shader is the easiest way to handle - // rotation and perspective and allows us to always generated quads in the - // font renderer which greatly simplifies the code, clipping in particular. - SkMatrix fontTransform; - bool linearFilter = findBestFontTransform(transform, &fontTransform) - || fabs(y - (int) y) > 0.0f - || fabs(x - (int) x) > 0.0f; - fontRenderer.setFont(paint, fontTransform); - fontRenderer.setTextureFiltering(linearFilter); - - // TODO: Implement better clipping for scaled/rotated text - const Rect* clip = !pureTranslate ? nullptr : &mState.currentRenderTargetClip(); - Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - - bool status; -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("unsupported"); - TextDrawFunctor functor(nullptr, nullptr, nullptr, x, y, pureTranslate, alpha, mode, paint); -#else - TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint); -#endif - - // don't call issuedrawcommand, do it at end of batch - bool forceFinish = (drawOpMode != DrawOpMode::kDefer); - if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) { - SkPaint paintCopy(*paint); - paintCopy.setTextAlign(SkPaint::kLeft_Align); - status = fontRenderer.renderPosText(&paintCopy, clip, glyphs, count, x, y, - positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish); - } else { - status = fontRenderer.renderPosText(paint, clip, glyphs, count, x, y, - positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish); - } - - if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) { - if (!pureTranslate) { - transform.mapRect(layerBounds); - } - dirtyLayerUnchecked(layerBounds, getRegion()); - } - - mDirty = true; -} - -void OpenGLRenderer::drawTextOnPath(const glyph_t* glyphs, int bytesCount, int count, - const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) { - if (glyphs == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) { - return; - } - - // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics - mRenderState.scissor().setEnabled(true); - - FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); - fontRenderer.setFont(paint, SkMatrix::I()); - fontRenderer.setTextureFiltering(true); - - int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha; - SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint); -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("unsupported"); - TextDrawFunctor functor(nullptr, nullptr, nullptr, 0.0f, 0.0f, false, alpha, mode, paint); -#else - TextDrawFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint); -#endif - - const Rect* clip = &writableSnapshot()->getLocalClip(); - Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - - if (fontRenderer.renderTextOnPath(paint, clip, glyphs, count, path, - hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) { - dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform()); - mDirty = true; - } -} - -void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) { - if (mState.currentlyIgnored()) return; - - mCaches.textureState().activateTexture(0); - - PathTexture* texture = mCaches.pathCache.get(path, paint); - if (!texture) return; - - const float x = texture->left - texture->offset; - const float y = texture->top - texture->offset; - - drawPathTexture(texture, x, y, paint); - - if (texture->cleanup) { - mCaches.pathCache.remove(path, paint); - } - mDirty = true; -} - -void OpenGLRenderer::drawLayer(Layer* layer) { - if (!layer) { - return; - } - - mat4* transform = nullptr; - if (layer->isTextureLayer()) { - transform = &layer->getTransform(); - if (!transform->isIdentity()) { - save(SaveFlags::Matrix); - concatMatrix(*transform); - } - } - - bool clipRequired = false; - const bool rejected = mState.calculateQuickRejectForScissor( - 0, 0, layer->layer.getWidth(), layer->layer.getHeight(), - &clipRequired, nullptr, false); - - if (rejected) { - if (transform && !transform->isIdentity()) { - restore(); - } - return; - } - - EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y, - x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired); - - updateLayer(layer, true); - - mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); - mCaches.textureState().activateTexture(0); - - if (CC_LIKELY(!layer->region.isEmpty())) { - if (layer->region.isRect()) { - DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, - composeLayerRect(layer, layer->regionRect)); - } else if (layer->mesh) { - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount) - .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewOffsetRectSnap(0, 0, Rect(layer->layer.getWidth(), layer->layer.getHeight())) - .build(); - DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop)); -#if DEBUG_LAYERS_AS_REGIONS - drawRegionRectsDebug(layer->region); -#endif - } - - if (layer->debugDrawUpdate) { - layer->debugDrawUpdate = false; - - SkPaint paint; - paint.setColor(0x7f00ff00); - drawColorRect(0, 0, layer->layer.getWidth(), layer->layer.getHeight(), &paint); - } - } - layer->hasDrawnSinceUpdate = true; - - if (transform && !transform->isIdentity()) { - restore(); - } - - mDirty = true; -} - -/////////////////////////////////////////////////////////////////////////////// -// Draw filters -/////////////////////////////////////////////////////////////////////////////// -void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) { - // We should never get here since we apply the draw filter when stashing - // the paints in the DisplayList. - LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters"); -} - -/////////////////////////////////////////////////////////////////////////////// -// Drawing implementation -/////////////////////////////////////////////////////////////////////////////// - -Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) { - Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef()); - if (!texture) { - return mCaches.textureCache.get(bitmap); - } - return texture; -} - -void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y, - const SkPaint* paint) { - if (quickRejectSetupScissor(x, y, x + texture->width(), y + texture->height())) { - return; - } - - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUnitQuad(nullptr) - .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRect(Rect(x, y, x + texture->width(), y + texture->height())) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) { - if (mState.currentlyIgnored()) { - return; - } - - drawColorRects(rects, count, paint, false, true, true); -} - -void OpenGLRenderer::drawShadow(float casterAlpha, - const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) { - if (mState.currentlyIgnored()) return; - - // TODO: use quickRejectWithScissor. For now, always force enable scissor. - mRenderState.scissor().setEnabled(true); - - SkPaint paint; - paint.setAntiAlias(true); // want to use AlphaVertex - - // The caller has made sure casterAlpha > 0. - float ambientShadowAlpha = mAmbientShadowAlpha; - if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) { - ambientShadowAlpha = Properties::overrideAmbientShadowStrength; - } - if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) { - paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0); - drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp); - } - - float spotShadowAlpha = mSpotShadowAlpha; - if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) { - spotShadowAlpha = Properties::overrideSpotShadowStrength; - } - if (spotShadowVertexBuffer && spotShadowAlpha > 0) { - paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0); - drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp); - } - - mDirty=true; -} - -void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint, - bool ignoreTransform, bool dirty, bool clip) { - if (count == 0) { - return; - } - - float left = FLT_MAX; - float top = FLT_MAX; - float right = FLT_MIN; - float bottom = FLT_MIN; - - Vertex mesh[count]; - Vertex* vertex = mesh; - - for (int index = 0; index < count; index += 4) { - float l = rects[index + 0]; - float t = rects[index + 1]; - float r = rects[index + 2]; - float b = rects[index + 3]; - - Vertex::set(vertex++, l, t); - Vertex::set(vertex++, r, t); - Vertex::set(vertex++, l, b); - Vertex::set(vertex++, r, b); - - left = std::min(left, l); - top = std::min(top, t); - right = std::max(right, r); - bottom = std::max(bottom, b); - } - - if (clip && quickRejectSetupScissor(left, top, right, bottom)) { - return; - } - - const int transformFlags = ignoreTransform - ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshIndexedQuads(&mesh[0], count / 4) - .setFillPaint(*paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom)) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, - const SkPaint* paint, bool ignoreTransform) { - const int transformFlags = ignoreTransform - ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshUnitQuad() - .setFillPaint(*paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewMapUnitToRect(Rect(left, top, right, bottom)) - .build(); - renderGlop(glop); -} - -float OpenGLRenderer::getLayerAlpha(const Layer* layer) const { - return (layer->getAlpha() / 255.0f) * currentSnapshot()->alpha; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h deleted file mode 100755 index dacd8ccaa6ea..000000000000 --- a/libs/hwui/OpenGLRenderer.h +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_OPENGL_RENDERER_H -#define ANDROID_HWUI_OPENGL_RENDERER_H - -#include "CanvasState.h" -#include "Debug.h" -#include "Extensions.h" -#include "Matrix.h" -#include "Program.h" -#include "Rect.h" -#include "Snapshot.h" -#include "UvMapper.h" -#include "Vertex.h" -#include "Caches.h" -#include "utils/PaintUtils.h" - -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -#include <SkBitmap.h> -#include <SkCanvas.h> -#include <SkColorFilter.h> -#include <SkDrawLooper.h> -#include <SkMatrix.h> -#include <SkPaint.h> -#include <SkRegion.h> -#include <SkXfermode.h> - -#include <utils/Blur.h> -#include <utils/Functor.h> -#include <utils/RefBase.h> -#include <utils/SortedVector.h> - -#include <cutils/compiler.h> - -#include <androidfw/ResourceTypes.h> - -#include <vector> - -class SkShader; - -namespace android { -namespace uirenderer { - -enum class DrawOpMode { - kImmediate, - kDefer, - kFlush -}; - -class DeferredDisplayState; -struct Glop; -class RenderState; -class RenderNode; -class TextDrawFunctor; -class VertexBuffer; - -enum StateDeferFlags { - kStateDeferFlag_Draw = 0x1, - kStateDeferFlag_Clip = 0x2 -}; - -enum ClipSideFlags { - kClipSide_None = 0x0, - kClipSide_Left = 0x1, - kClipSide_Top = 0x2, - kClipSide_Right = 0x4, - kClipSide_Bottom = 0x8, - kClipSide_Full = 0xF, - kClipSide_ConservativeFull = 0x1F -}; - -enum VertexBufferDisplayFlags { - kVertexBuffer_Offset = 0x1, - kVertexBuffer_ShadowInterp = 0x2, -}; - -/** - * Defines additional transformation that should be applied by the model view matrix, beyond that of - * the currentTransform() - */ -enum ModelViewMode { - /** - * Used when the model view should simply translate geometry passed to the shader. The resulting - * matrix will be a simple translation. - */ - kModelViewMode_Translate = 0, - - /** - * Used when the model view should translate and scale geometry. The resulting matrix will be a - * translation + scale. This is frequently used together with VBO 0, the (0,0,1,1) rect. - */ - kModelViewMode_TranslateAndScale = 1, -}; - -/////////////////////////////////////////////////////////////////////////////// -// Renderer -/////////////////////////////////////////////////////////////////////////////// -/** - * OpenGL Renderer implementation. - */ -class OpenGLRenderer : public CanvasStateClient { -public: - OpenGLRenderer(RenderState& renderState); - virtual ~OpenGLRenderer(); - - void initProperties(); - void initLight(float lightRadius, uint8_t ambientShadowAlpha, - uint8_t spotShadowAlpha); - void setLightCenter(const Vector3& lightCenter); - - /* - * Prepares the renderer to draw a frame. This method must be invoked - * at the beginning of each frame. Only the specified rectangle of the - * frame is assumed to be dirty. A clip will automatically be set to - * the specified rectangle. - * - * @param opaque If true, the target surface is considered opaque - * and will not be cleared. If false, the target surface - * will be cleared - */ - virtual void prepareDirty(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque); - - /** - * Indicates the end of a frame. This method must be invoked whenever - * the caller is done rendering a frame. - * Returns true if any drawing was done during the frame (the output - * has changed / is "dirty" and should be displayed to the user). - */ - virtual bool finish(); - - void callDrawGLFunction(Functor* functor, Rect& dirty); - - void pushLayerUpdate(Layer* layer); - void cancelLayerUpdate(Layer* layer); - void flushLayerUpdates(); - void markLayersAsBuildLayers(); - - virtual int saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags) { - return saveLayer(left, top, right, bottom, paint, flags, nullptr); - } - - // Specialized saveLayer implementation, which will pass the convexMask to an FBO layer, if - // created, which will in turn clip to that mask when drawn back/restored. - int saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags, const SkPath* convexMask); - - int saveLayerDeferred(float left, float top, float right, float bottom, - const SkPaint* paint, int flags); - - void drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1); - void drawLayer(Layer* layer); - void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint); - void drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount, - TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint); - void drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, - const SkPaint* paint); - void drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint); - void drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry, - TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint); - void drawPatch(const SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry, - float left, float top, float right, float bottom, const SkPaint* paint); - void drawColor(int color, SkXfermode::Mode mode); - void drawRect(float left, float top, float right, float bottom, - const SkPaint* paint); - void drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint* paint); - void drawCircle(float x, float y, float radius, const SkPaint* paint); - void drawOval(float left, float top, float right, float bottom, - const SkPaint* paint); - void drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint); - void drawPath(const SkPath* path, const SkPaint* paint); - void drawLines(const float* points, int count, const SkPaint* paint); - void drawPoints(const float* points, int count, const SkPaint* paint); - void drawTextOnPath(const glyph_t* glyphs, int bytesCount, int count, const SkPath* path, - float hOffset, float vOffset, const SkPaint* paint); - void drawText(const glyph_t* glyphs, int bytesCount, int count, float x, float y, - const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds, - DrawOpMode drawOpMode = DrawOpMode::kImmediate); - void drawRects(const float* rects, int count, const SkPaint* paint); - - void drawShadow(float casterAlpha, - const VertexBuffer* ambientShadowVertexBuffer, - const VertexBuffer* spotShadowVertexBuffer); - - void setDrawFilter(SkDrawFilter* filter); - - /** - * Store the current display state (most importantly, the current clip and transform), and - * additionally map the state's bounds from local to window coordinates. - * - * Returns true if quick-rejected - */ - bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags); - void restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore = false); - void setupMergedMultiDraw(const Rect* clipRect); - - bool isCurrentTransformSimple() { - return currentTransform()->isSimple(); - } - - Caches& getCaches() { - return mCaches; - } - - RenderState& renderState() { - return mRenderState; - } - - int getViewportWidth() { return mState.getViewportWidth(); } - int getViewportHeight() { return mState.getViewportHeight(); } - - /** - * Scales the alpha on the current snapshot. This alpha value will be modulated - * with other alpha values when drawing primitives. - */ - void scaleAlpha(float alpha) { mState.scaleAlpha(alpha); } - - /** - * Inserts a named event marker in the stream of GL commands. - */ - void eventMark(const char* name) const; - - /** - * Inserts a formatted event marker in the stream of GL commands. - */ - void eventMarkDEBUG(const char *fmt, ...) const; - - /** - * Inserts a named group marker in the stream of GL commands. This marker - * can be used by tools to group commands into logical groups. A call to - * this method must always be followed later on by a call to endMark(). - */ - void startMark(const char* name) const; - - /** - * Closes the last group marker opened by startMark(). - */ - void endMark() const; - - /** - * Build the best transform to use to rasterize text given a full - * transform matrix, and whether filteration is needed. - * - * Returns whether filtration is needed - */ - bool findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const; - -#if DEBUG_MERGE_BEHAVIOR - void drawScreenSpaceColorRect(float left, float top, float right, float bottom, int color) { - mCaches.setScissorEnabled(false); - - // should only be called outside of other draw ops, so stencil can only be in test state - bool stencilWasEnabled = mCaches.stencil.isTestEnabled(); - mCaches.stencil.disable(); - - drawColorRect(left, top, right, bottom, color, SkXfermode::kSrcOver_Mode, true); - - if (stencilWasEnabled) mCaches.stencil.enableTest(); - mDirty = true; - } -#endif - - const Vector3& getLightCenter() const { return mState.currentLightCenter(); } - float getLightRadius() const { return mLightRadius; } - uint8_t getAmbientShadowAlpha() const { return mAmbientShadowAlpha; } - uint8_t getSpotShadowAlpha() const { return mSpotShadowAlpha; } - - /////////////////////////////////////////////////////////////////// - /// State manipulation - - int getSaveCount() const; - int save(int flags); - void restore(); - void restoreToCount(int saveCount); - - void setGlobalMatrix(const Matrix4& matrix) { - mState.setMatrix(matrix); - } - void setLocalMatrix(const Matrix4& matrix); - void setLocalMatrix(const SkMatrix& matrix); - void concatMatrix(const SkMatrix& matrix) { mState.concatMatrix(matrix); } - - void translate(float dx, float dy, float dz = 0.0f); - void rotate(float degrees); - void scale(float sx, float sy); - void skew(float sx, float sy); - - void setMatrix(const Matrix4& matrix); // internal only convenience method - void concatMatrix(const Matrix4& matrix); // internal only convenience method - - const Rect& getLocalClipBounds() const { return mState.getLocalClipBounds(); } - const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); } - bool quickRejectConservative(float left, float top, - float right, float bottom) const { - return mState.quickRejectConservative(left, top, right, bottom); - } - - bool clipRect(float left, float top, - float right, float bottom, SkRegion::Op op); - bool clipPath(const SkPath* path, SkRegion::Op op); - bool clipRegion(const SkRegion* region, SkRegion::Op op); - - /** - * Does not support different clipping Ops (that is, every call to setClippingOutline is - * effectively using SkRegion::kReplaceOp) - * - * The clipping outline is independent from the regular clip. - */ - void setClippingOutline(LinearAllocator& allocator, const Outline* outline); - void setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius, bool highPriority = true); - void setProjectionPathMask(LinearAllocator& allocator, const SkPath* path); - - inline bool hasRectToRectTransform() const { return mState.hasRectToRectTransform(); } - inline const mat4* currentTransform() const { return mState.currentTransform(); } - - /////////////////////////////////////////////////////////////////// - /// CanvasStateClient interface - - virtual void onViewportInitialized() override; - virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override; - virtual GLuint getTargetFbo() const override { return 0; } - - SkPath* allocPathForFrame() { - std::unique_ptr<SkPath> path(new SkPath()); - SkPath* returnPath = path.get(); - mTempPaths.push_back(std::move(path)); - return returnPath; - } - - void setBaseTransform(const Matrix4& matrix) { mBaseTransform = matrix; } - -protected: - /** - * Perform the setup specific to a frame. This method does not - * issue any OpenGL commands. - */ - void setupFrameState(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque); - - /** - * Indicates the start of rendering. This method will setup the - * initial OpenGL state (viewport, clearing the buffer, etc.) - */ - void startFrame(); - - /** - * Clears the underlying surface if needed. - */ - virtual void clear(float left, float top, float right, float bottom, bool opaque); - - /** - * Call this method after updating a layer during a drawing pass. - */ - void resumeAfterLayer(); - - /** - * This method is called whenever a stencil buffer is required. Subclasses - * should override this method and call attachStencilBufferToLayer() on the - * appropriate layer(s). - */ - virtual void ensureStencilBuffer(); - - /** - * Obtains a stencil render buffer (allocating it if necessary) and - * attaches it to the specified layer. - */ - void attachStencilBufferToLayer(Layer* layer); - - /** - * Draw a rectangle list. Currently only used for the the stencil buffer so that the stencil - * will have a value of 'n' in every unclipped pixel, where 'n' is the number of rectangles - * in the list. - */ - void drawRectangleList(const RectangleList& rectangleList); - - bool quickRejectSetupScissor(float left, float top, float right, float bottom, - const SkPaint* paint = nullptr); - bool quickRejectSetupScissor(const Rect& bounds, const SkPaint* paint = nullptr) { - return quickRejectSetupScissor(bounds.left, bounds.top, - bounds.right, bounds.bottom, paint); - } - - /** - * Compose the layer defined in the current snapshot with the layer - * defined by the previous snapshot. - * - * The current snapshot *must* be a layer (flag kFlagIsLayer set.) - * - * @param curent The current snapshot containing the layer to compose - * @param previous The previous snapshot to compose the current layer with - */ - virtual void composeLayer(const Snapshot& current, const Snapshot& previous); - - /** - * Marks the specified region as dirty at the specified bounds. - */ - void dirtyLayerUnchecked(Rect& bounds, Region* region); - - /** - * Returns the region of the current layer. - */ - virtual Region* getRegion() const { - return mState.currentRegion(); - } - - /** - * Indicates whether rendering is currently targeted at a layer. - */ - virtual bool hasLayer() const { - return (mState.currentFlags() & Snapshot::kFlagFboTarget) && mState.currentRegion(); - } - - /** - * Renders the specified layer as a textured quad. - * - * @param layer The layer to render - * @param rect The bounds of the layer - */ - void drawTextureLayer(Layer* layer, const Rect& rect); - - /** - * Gets the alpha from a layer, accounting for snapshot alpha - * - * @param layer The layer from which the alpha is extracted - */ - inline float getLayerAlpha(const Layer* layer) const; - - /** - * Set to true to suppress error checks at the end of a frame. - */ - virtual bool suppressErrorChecks() const { - return false; - } - - CanvasState mState; - Caches& mCaches; - RenderState& mRenderState; - -private: - enum class GlopRenderType { - Standard, - Multi, - LayerClear - }; - - void renderGlop(const Glop& glop, GlopRenderType type = GlopRenderType::Standard); - - /** - * Discards the content of the framebuffer if supported by the driver. - * This method should be called at the beginning of a frame to optimize - * rendering on some tiler architectures. - */ - void discardFramebuffer(float left, float top, float right, float bottom); - - /** - * Sets the clipping rectangle using glScissor. The clip is defined by - * the current snapshot's clipRect member. - */ - void setScissorFromClip(); - - /** - * Sets the clipping region using the stencil buffer. The clip region - * is defined by the current snapshot's clipRegion member. - */ - void setStencilFromClip(); - - /** - * Given the local bounds of the layer, calculates ... - */ - void calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer); - - /** - * Given the local bounds + clip of the layer, updates current snapshot's empty/invisible - */ - void updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip, - bool fboLayer, int alpha); - - /** - * Creates a new layer stored in the specified snapshot. - * - * @param snapshot The snapshot associated with the new layer - * @param left The left coordinate of the layer - * @param top The top coordinate of the layer - * @param right The right coordinate of the layer - * @param bottom The bottom coordinate of the layer - * @param alpha The translucency of the layer - * @param mode The blending mode of the layer - * @param flags The layer save flags - * @param mask A mask to use when drawing the layer back, may be empty - * - * @return True if the layer was successfully created, false otherwise - */ - bool createLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags, const SkPath* convexMask); - - /** - * Creates a new layer stored in the specified snapshot as an FBO. - * - * @param layer The layer to store as an FBO - * @param snapshot The snapshot associated with the new layer - * @param bounds The bounds of the layer - */ - bool createFboLayer(Layer* layer, Rect& bounds, Rect& clip); - - /** - * Compose the specified layer as a region. - * - * @param layer The layer to compose - * @param rect The layer's bounds - */ - void composeLayerRegion(Layer* layer, const Rect& rect); - - /** - * Restores the content in layer to the screen, swapping the blend mode, - * specifically used in the restore() of a saveLayerAlpha(). - * - * This allows e.g. a layer that would have been drawn on top of existing content (with SrcOver) - * to be drawn underneath. - * - * This will always ignore the canvas transform. - */ - void composeLayerRectSwapped(Layer* layer, const Rect& rect); - - /** - * Draws the content in layer to the screen. - */ - void composeLayerRect(Layer* layer, const Rect& rect); - - /** - * Clears all the regions corresponding to the current list of layers. - * This method MUST be invoked before any drawing operation. - */ - void clearLayerRegions(); - - /** - * Mark the layer as dirty at the specified coordinates. The coordinates - * are transformed with the supplied matrix. - */ - void dirtyLayer(const float left, const float top, - const float right, const float bottom, const Matrix4& transform); - - /** - * Mark the layer as dirty at the specified coordinates. - */ - void dirtyLayer(const float left, const float top, - const float right, const float bottom); - - /** - * Draws a colored rectangle with the specified color. The specified coordinates - * are transformed by the current snapshot's transform matrix unless specified - * otherwise. - * - * @param left The left coordinate of the rectangle - * @param top The top coordinate of the rectangle - * @param right The right coordinate of the rectangle - * @param bottom The bottom coordinate of the rectangle - * @param paint The paint containing the color, blending mode, etc. - * @param ignoreTransform True if the current transform should be ignored - */ - void drawColorRect(float left, float top, float right, float bottom, - const SkPaint* paint, bool ignoreTransform = false); - - /** - * Draws a series of colored rectangles with the specified color. The specified - * coordinates are transformed by the current snapshot's transform matrix unless - * specified otherwise. - * - * @param rects A list of rectangles, 4 floats (left, top, right, bottom) - * per rectangle - * @param paint The paint containing the color, blending mode, etc. - * @param ignoreTransform True if the current transform should be ignored - * @param dirty True if calling this method should dirty the current layer - * @param clip True if the rects should be clipped, false otherwise - */ - void drawColorRects(const float* rects, int count, const SkPaint* paint, - bool ignoreTransform = false, bool dirty = true, bool clip = true); - - /** - * Draws the shape represented by the specified path texture. - * This method invokes drawPathTexture() but takes into account - * the extra left/top offset and the texture offset to correctly - * position the final shape. - * - * @param left The left coordinate of the shape to render - * @param top The top coordinate of the shape to render - * @param texture The texture reprsenting the shape - * @param paint The paint to draw the shape with - */ - void drawShape(float left, float top, PathTexture* texture, const SkPaint* paint); - - /** - * Renders a strip of polygons with the specified paint, used for tessellated geometry. - * - * @param vertexBuffer The VertexBuffer to be drawn - * @param paint The paint to render with - * @param flags flags with which to draw - */ - void drawVertexBuffer(float translateX, float translateY, const VertexBuffer& vertexBuffer, - const SkPaint* paint, int flags = 0); - - /** - * Convenience for translating method - */ - void drawVertexBuffer(const VertexBuffer& vertexBuffer, - const SkPaint* paint, int flags = 0) { - drawVertexBuffer(0.0f, 0.0f, vertexBuffer, paint, flags); - } - - /** - * Renders the convex hull defined by the specified path as a strip of polygons. - * - * @param path The hull of the path to draw - * @param paint The paint to render with - */ - void drawConvexPath(const SkPath& path, const SkPaint* paint); - - /** - * Draws shadow layer on text (with optional positions). - * - * @param paint The paint to draw the shadow with - * @param text The text to draw - * @param count The number of glyphs in the text - * @param positions The x, y positions of individual glyphs (or NULL) - * @param fontRenderer The font renderer object - * @param alpha The alpha value for drawing the shadow - * @param x The x coordinate where the shadow will be drawn - * @param y The y coordinate where the shadow will be drawn - */ - void drawTextShadow(const SkPaint* paint, const glyph_t* glyphs, int count, - const float* positions, FontRenderer& fontRenderer, int alpha, - float x, float y); - - /** - * Draws a path texture. Path textures are alpha8 bitmaps that need special - * compositing to apply colors/filters/etc. - * - * @param texture The texture to render - * @param x The x coordinate where the texture will be drawn - * @param y The y coordinate where the texture will be drawn - * @param paint The paint to draw the texture with - */ - void drawPathTexture(PathTexture* texture, float x, float y, const SkPaint* paint); - - /** - * Resets the texture coordinates stored in mMeshVertices. Setting the values - * back to default is achieved by calling: - * - * resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); - * - * @param u1 The left coordinate of the texture - * @param v1 The bottom coordinate of the texture - * @param u2 The right coordinate of the texture - * @param v2 The top coordinate of the texture - */ - void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2); - - /** - * Returns true if the specified paint will draw invisible text. - */ - bool canSkipText(const SkPaint* paint) const; - - bool updateLayer(Layer* layer, bool inFrame); - void updateLayers(); - void flushLayers(); - -#if DEBUG_LAYERS_AS_REGIONS - /** - * Renders the specified region as a series of rectangles. This method - * is used for debugging only. - */ - void drawRegionRectsDebug(const Region& region); -#endif - - /** - * Renders the specified region as a series of rectangles. The region - * must be in screen-space coordinates. - */ - void drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty = false); - - /** - * Draws the current clip region if any. Only when DEBUG_CLIP_REGIONS - * is turned on. - */ - void debugClip(); - - void debugOverdraw(bool enable, bool clear); - void renderOverdraw(); - void countOverdraw(); - - /** - * Should be invoked every time the glScissor is modified. - */ - inline void dirtyClip() { mState.setDirtyClip(true); } - - inline const UvMapper& getMapper(const Texture* texture) { - return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper; - } - - /** - * Returns a texture object for the specified bitmap. The texture can - * come from the texture cache or an atlas. If this method returns - * NULL, the texture could not be found and/or allocated. - */ - Texture* getTexture(const SkBitmap* bitmap); - - bool reportAndClearDirty() { bool ret = mDirty; mDirty = false; return ret; } - inline Snapshot* writableSnapshot() { return mState.writableSnapshot(); } - inline const Snapshot* currentSnapshot() const { return mState.currentSnapshot(); } - - // State used to define the clipping region - Rect mTilingClip; - // Is the target render surface opaque - bool mOpaque; - // Is a frame currently being rendered - bool mFrameStarted; - - // Default UV mapper - const UvMapper mUvMapper; - - // List of rectangles to clear after saveLayer() is invoked - std::vector<Rect> mLayers; - // List of layers to update at the beginning of a frame - std::vector< sp<Layer> > mLayerUpdates; - - // See PROPERTY_DISABLE_SCISSOR_OPTIMIZATION in - // Properties.h - bool mScissorOptimizationDisabled; - - bool mSkipOutlineClip; - - // True if anything has been drawn since the last call to - // reportAndClearDirty() - bool mDirty; - - // Lighting + shadows - Vector3 mLightCenter; - float mLightRadius; - uint8_t mAmbientShadowAlpha; - uint8_t mSpotShadowAlpha; - - // Paths kept alive for the duration of the frame - std::vector<std::unique_ptr<SkPath>> mTempPaths; - - /** - * Initial transform for a rendering pass; transform from global device - * coordinates to the current RenderNode's drawing content coordinates, - * with the RenderNode's RenderProperty transforms already applied. - * Calling setMatrix(mBaseTransform) will result in drawing at the origin - * of the DisplayList's recorded surface prior to any Canvas - * transformation. - */ - Matrix4 mBaseTransform; - - friend class Layer; - friend class TextDrawFunctor; - friend class DrawBitmapOp; - friend class DrawPatchOp; - -}; // class OpenGLRenderer - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_OPENGL_RENDERER_H diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp index bd6feb9fc762..a6c281dc9839 100644 --- a/libs/hwui/PatchCache.cpp +++ b/libs/hwui/PatchCache.cpp @@ -43,21 +43,6 @@ PatchCache::~PatchCache() { clear(); } -void PatchCache::init() { - bool created = false; - if (!mMeshBuffer) { - glGenBuffers(1, &mMeshBuffer); - created = true; - } - - mRenderState.meshState().bindMeshBuffer(mMeshBuffer); - mRenderState.meshState().resetVertexPointers(); - - if (created) { - createVertexBuffer(); - } -} - /////////////////////////////////////////////////////////////////////////////// // Caching /////////////////////////////////////////////////////////////////////////////// @@ -80,8 +65,7 @@ void PatchCache::clear() { clearCache(); if (mMeshBuffer) { - mRenderState.meshState().unbindMeshBuffer(); - glDeleteBuffers(1, &mMeshBuffer); + mRenderState.meshState().deleteMeshBuffer(mMeshBuffer); mMeshBuffer = 0; mSize = 0; } @@ -170,7 +154,8 @@ void PatchCache::clearGarbage() { } void PatchCache::createVertexBuffer() { - glBufferData(GL_ARRAY_BUFFER, mMaxSize, nullptr, GL_DYNAMIC_DRAW); + mRenderState.meshState().genOrUpdateMeshBuffer(&mMeshBuffer, + mMaxSize, nullptr, GL_DYNAMIC_DRAW); mSize = 0; mFreeBlocks = new BufferBlock(0, mMaxSize); mGenerationId++; @@ -182,7 +167,9 @@ void PatchCache::createVertexBuffer() { */ void PatchCache::setupMesh(Patch* newMesh) { // This call ensures the VBO exists and that it is bound - init(); + if (!mMeshBuffer) { + createVertexBuffer(); + } // If we're running out of space, let's clear the entire cache uint32_t size = newMesh->getSize(); @@ -215,7 +202,9 @@ void PatchCache::setupMesh(Patch* newMesh) { // Copy the 9patch mesh in the VBO newMesh->positionOffset = (GLintptr) (block->offset); newMesh->textureOffset = newMesh->positionOffset + kMeshTextureOffset; - glBufferSubData(GL_ARRAY_BUFFER, newMesh->positionOffset, size, newMesh->vertices.get()); + + mRenderState.meshState().updateMeshBufferSubData(mMeshBuffer, newMesh->positionOffset, size, + newMesh->vertices.get()); // Remove the block since we've used it entirely if (block->size == size) { diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h index 66ef6a0279ba..4e587fb719d4 100644 --- a/libs/hwui/PatchCache.h +++ b/libs/hwui/PatchCache.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_PATCH_CACHE_H -#define ANDROID_HWUI_PATCH_CACHE_H +#pragma once #include <GLES2/gl2.h> @@ -48,12 +47,12 @@ class Patch; /////////////////////////////////////////////////////////////////////////////// class Caches; +class RenderState; class PatchCache { public: PatchCache(RenderState& renderState); ~PatchCache(); - void init(); const Patch* get(const AssetAtlas::Entry* entry, const uint32_t bitmapWidth, const uint32_t bitmapHeight, @@ -187,5 +186,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_PATCH_CACHE_H diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 6f68c2bdff80..93b2e15a6590 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -63,8 +63,10 @@ int Properties::overrideSpotShadowStrength = -1; ProfileType Properties::sProfileType = ProfileType::None; bool Properties::sDisableProfileBars = false; +RenderPipelineType Properties::sRenderPipelineType = RenderPipelineType::NotInitialized; bool Properties::waitForGpuCompletion = false; +bool Properties::forceDrawFrame = false; bool Properties::filterOutTestOverhead = false; @@ -204,5 +206,21 @@ ProfileType Properties::getProfileType() { return sProfileType; } +RenderPipelineType Properties::getRenderPipelineType() { + if (RenderPipelineType::NotInitialized != sRenderPipelineType) { + return sRenderPipelineType; + } + char prop[PROPERTY_VALUE_MAX]; + property_get(PROPERTY_DEFAULT_RENDERER, prop, "opengl"); + if (!strcmp(prop, "skiagl") ) { + sRenderPipelineType = RenderPipelineType::SkiaGL; + } else if (!strcmp(prop, "skiavulkan") ) { + sRenderPipelineType = RenderPipelineType::SkiaVulkan; + } else { //"opengl" + sRenderPipelineType = RenderPipelineType::OpenGL; + } + return sRenderPipelineType; +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 8fec42972c2f..133ae809ab2c 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -20,8 +20,7 @@ #include <cutils/properties.h> /** - * This file contains the list of system properties used to configure - * the OpenGLRenderer. + * This file contains the list of system properties used to configure libhwui. */ namespace android { @@ -153,6 +152,12 @@ enum DebugLevel { #define PROPERTY_FILTER_TEST_OVERHEAD "debug.hwui.filter_test_overhead" +/** + * Allows to set rendering pipeline mode to OpenGL (default), Skia OpenGL + * or Vulkan. + */ +#define PROPERTY_DEFAULT_RENDERER "debug.hwui.default_renderer" + /////////////////////////////////////////////////////////////////////////////// // Runtime configuration properties /////////////////////////////////////////////////////////////////////////////// @@ -161,7 +166,7 @@ enum DebugLevel { * Used to enable/disable scissor optimization. The accepted values are * "true" and "false". The default value is "false". * - * When scissor optimization is enabled, OpenGLRenderer will attempt to + * When scissor optimization is enabled, libhwui will attempt to * minimize the use of scissor by selectively enabling and disabling the * GL scissor test. * When the optimization is disabled, OpenGLRenderer will keep the GL @@ -245,6 +250,13 @@ enum class StencilClipDebug { ShowRegion }; +enum class RenderPipelineType { + OpenGL = 0, + SkiaGL, + SkiaVulkan, + NotInitialized = 128 +}; + /** * Renderthread-only singleton which manages several static rendering properties. Most of these * are driven by system properties which are queried once at initialization, and again if init() @@ -292,9 +304,11 @@ public: static int overrideSpotShadowStrength; static ProfileType getProfileType(); + static RenderPipelineType getRenderPipelineType(); // Should be used only by test apps static bool waitForGpuCompletion; + static bool forceDrawFrame; // Should only be set by automated tests to try and filter out // any overhead they add @@ -303,6 +317,7 @@ public: private: static ProfileType sProfileType; static bool sDisableProfileBars; + static RenderPipelineType sRenderPipelineType; }; // class Caches diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index 55f823dfe226..60eadff66ad1 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -19,6 +19,7 @@ #include "Caches.h" #include "Image.h" #include "GlopBuilder.h" +#include "Layer.h" #include "renderstate/RenderState.h" #include "renderthread/EglManager.h" #include "utils/GLUtils.h" @@ -30,14 +31,8 @@ namespace android { namespace uirenderer { -CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread, - Surface& surface, SkBitmap* bitmap) { - // TODO: Clean this up and unify it with LayerRenderer::copyLayer, - // of which most of this is copied from. - renderThread.eglManager().initialize(); - - Caches& caches = Caches::getInstance(); - RenderState& renderState = renderThread.renderState(); +static CopyResult copyTextureInto(Caches& caches, RenderState& renderState, + Texture& sourceTexture, Matrix4& texTransform, SkBitmap* bitmap) { int destWidth = bitmap->width(); int destHeight = bitmap->height(); if (destWidth > caches.maxTextureSize @@ -98,6 +93,44 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); + { + // Draw & readback + renderState.setViewport(destWidth, destHeight); + renderState.scissor().setEnabled(false); + renderState.blend().syncEnabled(); + renderState.stencil().disable(); + + Glop glop; + GlopBuilder(renderState, caches, &glop) + .setRoundRectClipState(nullptr) + .setMeshTexturedUnitQuad(nullptr) + .setFillExternalTexture(sourceTexture, texTransform) + .setTransform(Matrix4::identity(), TransformFlags::None) + .setModelViewMapUnitToRect(Rect(destWidth, destHeight)) + .build(); + Matrix4 ortho; + ortho.loadOrtho(destWidth, destHeight); + renderState.render(glop, ortho); + + glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, + type, bitmap->getPixels()); + } + + // Cleanup + caches.textureState().deleteTexture(texture); + renderState.deleteFramebuffer(fbo); + + GL_CHECKPOINT(MODERATE); + + return CopyResult::Success; +} + +CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread, + Surface& surface, SkBitmap* bitmap) { + renderThread.eglManager().initialize(); + + Caches& caches = Caches::getInstance(); + // Setup the source sp<GraphicBuffer> sourceBuffer; sp<Fence> sourceFence; @@ -142,7 +175,7 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread, GLuint sourceTexId; // Create a 2D texture to sample from the EGLImage glGenTextures(1, &sourceTexId); - Caches::getInstance().textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId); + caches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId); glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, sourceImage); GLenum status = GL_NO_ERROR; @@ -155,37 +188,13 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread, sourceTexture.wrap(sourceTexId, sourceBuffer->getWidth(), sourceBuffer->getHeight(), 0 /* total lie */); - { - // Draw & readback - renderState.setViewport(destWidth, destHeight); - renderState.scissor().setEnabled(false); - renderState.blend().syncEnabled(); - renderState.stencil().disable(); - - Rect destRect(destWidth, destHeight); - Glop glop; - GlopBuilder(renderState, caches, &glop) - .setRoundRectClipState(nullptr) - .setMeshTexturedUnitQuad(nullptr) - .setFillExternalTexture(sourceTexture, texTransform) - .setTransform(Matrix4::identity(), TransformFlags::None) - .setModelViewMapUnitToRect(destRect) - .build(); - Matrix4 ortho; - ortho.loadOrtho(destWidth, destHeight); - renderState.render(glop, ortho); - - glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, - type, bitmap->getPixels()); - } - - // Cleanup - caches.textureState().deleteTexture(texture); - renderState.deleteFramebuffer(fbo); - - GL_CHECKPOINT(MODERATE); + return copyTextureInto(caches, renderThread.renderState(), sourceTexture, texTransform, bitmap); +} - return CopyResult::Success; +CopyResult Readback::copyTextureLayerInto(renderthread::RenderThread& renderThread, + Layer& layer, SkBitmap* bitmap) { + return copyTextureInto(Caches::getInstance(), renderThread.renderState(), + layer.getTexture(), layer.getTexTransform(), bitmap); } } // namespace uirenderer diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h index a112c42988c0..bd73734949f3 100644 --- a/libs/hwui/Readback.h +++ b/libs/hwui/Readback.h @@ -24,6 +24,8 @@ namespace android { namespace uirenderer { +class Layer; + // Keep in sync with PixelCopy.java codes enum class CopyResult { Success = 0, @@ -36,8 +38,18 @@ enum class CopyResult { class Readback { public: + /** + * Copies the surface's most recently queued buffer into the provided bitmap. + */ static CopyResult copySurfaceInto(renderthread::RenderThread& renderThread, Surface& surface, SkBitmap* bitmap); + + /** + * Copies the TextureLayer's texture content (thus, the currently rendering buffer) into the + * provided bitmap. + */ + static CopyResult copyTextureLayerInto(renderthread::RenderThread& renderThread, + Layer& layer, SkBitmap* bitmap); }; } // namespace uirenderer diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index aee9d6370083..f3078ce58503 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -14,16 +14,15 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_RECORDED_OP_H -#define ANDROID_HWUI_RECORDED_OP_H +#pragma once -#include "RecordedOp.h" #include "font/FontUtil.h" #include "Matrix.h" #include "Rect.h" #include "RenderNode.h" #include "TessellationCache.h" #include "utils/LinearAllocator.h" +#include "utils/PaintUtils.h" #include "Vector.h" #include <androidfw/ResourceTypes.h> @@ -529,5 +528,3 @@ struct LayerOp : RecordedOp { }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_RECORDED_OP_H diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index cbefccb955de..4528a3876177 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -43,7 +43,6 @@ void RecordingCanvas::resetRecording(int width, int height) { mState.initializeRecordingSaveStack(width, height); mDeferredBarrierType = DeferredBarrierType::InOrder; - mState.setDirtyClip(false); } DisplayList* RecordingCanvas::finishRecording() { diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 6facf20b025c..ff277d111197 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -16,19 +16,17 @@ #include "RenderNode.h" +#include "BakedOpRenderer.h" #include "DamageAccumulator.h" #include "Debug.h" -#if HWUI_NEW_OPS -#include "BakedOpRenderer.h" -#include "RecordedOp.h" -#include "OpDumper.h" -#endif -#include "DisplayListOp.h" #include "LayerRenderer.h" -#include "OpenGLRenderer.h" +#include "OpDumper.h" +#include "RecordedOp.h" #include "TreeInfo.h" #include "utils/MathUtils.h" #include "utils/TraceUtils.h" +#include "VectorDrawable.h" +#include "renderstate/RenderState.h" #include "renderthread/CanvasContext.h" #include "protos/hwui.pb.h" @@ -41,23 +39,6 @@ namespace android { namespace uirenderer { -void RenderNode::debugDumpLayers(const char* prefix) { -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("TODO: dump layer"); -#else - if (mLayer) { - ALOGD("%sNode %p (%s) has layer %p (fbo = %u, wasBuildLayered = %s)", - prefix, this, getName(), mLayer, mLayer->getFbo(), - mLayer->wasBuildLayered ? "true" : "false"); - } -#endif - if (mDisplayList) { - for (auto&& child : mDisplayList->getChildren()) { - child->renderNode->debugDumpLayers(prefix); - } - } -} - RenderNode::RenderNode() : mDirtyPropertyFields(0) , mNeedsDisplayListSync(false) @@ -70,15 +51,7 @@ RenderNode::RenderNode() RenderNode::~RenderNode() { deleteDisplayList(nullptr); delete mStagingDisplayList; -#if HWUI_NEW_OPS LOG_ALWAYS_FATAL_IF(mLayer, "layer missed detachment!"); -#else - if (mLayer) { - ALOGW("Memory Warning: Layer %p missed its detachment, held on to for far too long!", mLayer); - mLayer->postDecStrong(); - mLayer = nullptr; - } -#endif } void RenderNode::setStagingDisplayList(DisplayList* displayList, TreeObserver* observer) { @@ -96,7 +69,6 @@ void RenderNode::setStagingDisplayList(DisplayList* displayList, TreeObserver* o * This function is a simplified version of replay(), where we simply retrieve and log the * display list. This function should remain in sync with the replay() function. */ -#if HWUI_NEW_OPS void RenderNode::output(uint32_t level, const char* label) { ALOGD("%s (%s %p%s%s%s%s%s)", label, @@ -123,26 +95,6 @@ void RenderNode::output(uint32_t level, const char* label) { } ALOGD("%*s/RenderNode(%s %p)", level * 2, "", getName(), this); } -#else -void RenderNode::output(uint32_t level) { - ALOGD("%*sStart display list (%p, %s%s%s%s%s%s)", (level - 1) * 2, "", this, - getName(), - (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : ""), - (properties().hasShadow() ? ", casting shadow" : ""), - (isRenderable() ? "" : ", empty"), - (properties().getProjectBackwards() ? ", projected" : ""), - (mLayer != nullptr ? ", on HW Layer" : "")); - ALOGD("%*s%s %d", level * 2, "", "Save", SaveFlags::MatrixClip); - properties().debugOutputProperties(level); - if (mDisplayList) { - // TODO: consider printing the chunk boundaries here - for (auto&& op : mDisplayList->getOps()) { - op->output(level, DisplayListOp::kOpLogFlag_Recurse); - } - } - ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName()); - } -#endif void RenderNode::copyTo(proto::RenderNode *pnode) { pnode->set_id(static_cast<uint64_t>( @@ -272,29 +224,17 @@ void RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) { } } -static layer_t* createLayer(RenderState& renderState, uint32_t width, uint32_t height) { -#if HWUI_NEW_OPS +static OffscreenBuffer* createLayer(RenderState& renderState, uint32_t width, uint32_t height) { return renderState.layerPool().get(renderState, width, height); -#else - return LayerRenderer::createRenderLayer(renderState, width, height); -#endif } -static void destroyLayer(layer_t* layer) { -#if HWUI_NEW_OPS +static void destroyLayer(OffscreenBuffer* layer) { RenderState& renderState = layer->renderState; renderState.layerPool().putOrDelete(layer); -#else - LayerRenderer::destroyLayer(layer); -#endif } -static bool layerMatchesWidthAndHeight(layer_t* layer, int width, int height) { -#if HWUI_NEW_OPS +static bool layerMatchesWidthAndHeight(OffscreenBuffer* layer, int width, int height) { return layer->viewportWidth == (uint32_t) width && layer->viewportHeight == (uint32_t)height; -#else - return layer->layer.getWidth() == width && layer->layer.getHeight() == height; -#endif } void RenderNode::pushLayerUpdate(TreeInfo& info) { @@ -315,22 +255,15 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) { bool transformUpdateNeeded = false; if (!mLayer) { mLayer = createLayer(info.canvasContext.getRenderState(), getWidth(), getHeight()); -#if !HWUI_NEW_OPS - applyLayerPropertiesToLayer(info); -#endif damageSelf(info); transformUpdateNeeded = true; } else if (!layerMatchesWidthAndHeight(mLayer, getWidth(), getHeight())) { -#if HWUI_NEW_OPS // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering) // Or, ideally, maintain damage between frames on node/layer so ordering is always correct RenderState& renderState = mLayer->renderState; if (properties().fitsOnLayer()) { mLayer = renderState.layerPool().resize(mLayer, getWidth(), getHeight()); } else { -#else - if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) { -#endif destroyLayer(mLayer); mLayer = nullptr; } @@ -365,19 +298,7 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) { mLayer->setWindowTransform(windowTransform); } -#if HWUI_NEW_OPS info.layerUpdateQueue->enqueueLayerWithDamage(this, dirty); -#else - if (dirty.intersect(0, 0, getWidth(), getHeight())) { - dirty.roundOut(&dirty); - mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom); - } - // This is not inside the above if because we may have called - // updateDeferred on a previous prepare pass that didn't have a renderer - if (info.renderer && mLayer->deferredUpdateScheduled) { - info.renderer->pushLayerUpdate(mLayer); - } -#endif // There might be prefetched layers that need to be accounted for. // That might be us, so tell CanvasContext that this layer is in the @@ -453,9 +374,6 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) { damageSelf(info); info.damageAccumulator->popTransform(); syncProperties(); -#if !HWUI_NEW_OPS - applyLayerPropertiesToLayer(info); -#endif // We could try to be clever and only re-damage if the matrix changed. // However, we don't need to worry about that. The cost of over-damaging // here is only going to be a single additional map rect of this node @@ -466,17 +384,6 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) { } } -#if !HWUI_NEW_OPS -void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) { - if (CC_LIKELY(!mLayer)) return; - - const LayerProperties& props = properties().layerProperties(); - mLayer->setAlpha(props.alpha(), props.xferMode()); - mLayer->setColorFilter(props.colorFilter()); - mLayer->setBlend(props.needsBlending()); -} -#endif - void RenderNode::syncDisplayList(TreeInfo* info) { // Make sure we inc first so that we don't fluctuate between 0 and 1, // which would thrash the layer cache @@ -529,15 +436,8 @@ void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayL } for (auto&& op : subtree->getChildren()) { RenderNode* childNode = op->renderNode; -#if HWUI_NEW_OPS info.damageAccumulator->pushTransform(&op->localMatrix); bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip; -#else - info.damageAccumulator->pushTransform(&op->localMatrix); - bool childFunctorsNeedLayer = functorsNeedLayer - // Recorded with non-rect clip, or canvas-rotated by parent - || op->mRecordedWithPotentialStencilClip; -#endif childNode->prepareTreeImpl(info, childFunctorsNeedLayer); info.damageAccumulator->popTransform(); } @@ -579,84 +479,6 @@ void RenderNode::decParentRefCount(TreeObserver* observer, TreeInfo* info) { } } -/* - * For property operations, we pass a savecount of 0, since the operations aren't part of the - * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in - * base saveCount (i.e., how RestoreToCount uses saveCount + properties().getCount()) - */ -#define PROPERTY_SAVECOUNT 0 - -template <class T> -void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) { -#if DEBUG_DISPLAY_LIST - properties().debugOutputProperties(handler.level() + 1); -#endif - if (properties().getLeft() != 0 || properties().getTop() != 0) { - renderer.translate(properties().getLeft(), properties().getTop()); - } - if (properties().getStaticMatrix()) { - renderer.concatMatrix(*properties().getStaticMatrix()); - } else if (properties().getAnimationMatrix()) { - renderer.concatMatrix(*properties().getAnimationMatrix()); - } - if (properties().hasTransformMatrix()) { - if (properties().isTransformTranslateOnly()) { - renderer.translate(properties().getTranslationX(), properties().getTranslationY()); - } else { - renderer.concatMatrix(*properties().getTransformMatrix()); - } - } - const bool isLayer = properties().effectiveLayerType() != LayerType::None; - int clipFlags = properties().getClippingFlags(); - if (properties().getAlpha() < 1) { - if (isLayer) { - clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer - } - if (CC_LIKELY(isLayer || !properties().getHasOverlappingRendering())) { - // simply scale rendering content's alpha - renderer.scaleAlpha(properties().getAlpha()); - } else { - // savelayer needed to create an offscreen buffer - Rect layerBounds(0, 0, getWidth(), getHeight()); - if (clipFlags) { - properties().getClippingRectForFlags(clipFlags, &layerBounds); - clipFlags = 0; // all clipping done by savelayer - } - SaveLayerOp* op = new (handler.allocator()) SaveLayerOp( - layerBounds.left, layerBounds.top, - layerBounds.right, layerBounds.bottom, - (int) (properties().getAlpha() * 255), - SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer); - handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); - } - - if (CC_UNLIKELY(ATRACE_ENABLED() && properties().promotedToLayer())) { - // pretend alpha always causes savelayer to warn about - // performance problem affecting old versions - ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", getName(), - static_cast<int>(getWidth()), - static_cast<int>(getHeight())); - } - } - if (clipFlags) { - Rect clipRect; - properties().getClippingRectForFlags(clipFlags, &clipRect); - ClipRectOp* op = new (handler.allocator()) ClipRectOp( - clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, - SkRegion::kIntersect_Op); - handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); - } - - // TODO: support nesting round rect clips - if (mProperties.getRevealClip().willClip()) { - Rect bounds; - mProperties.getRevealClip().getBounds(&bounds); - renderer.setClippingRoundRect(handler.allocator(), bounds, mProperties.getRevealClip().getRadius()); - } else if (mProperties.getOutline().willClip()) { - renderer.setClippingOutline(handler.allocator(), &(mProperties.getOutline())); - } -} - /** * Apply property-based transformations to input matrix * @@ -717,14 +539,14 @@ void RenderNode::computeOrdering() { // transform properties are applied correctly to top level children if (mDisplayList == nullptr) return; for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) { - renderNodeOp_t* childOp = mDisplayList->getChildren()[i]; + RenderNodeOp* childOp = mDisplayList->getChildren()[i]; childOp->renderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity()); } } void RenderNode::computeOrderingImpl( - renderNodeOp_t* opState, - std::vector<renderNodeOp_t*>* compositedChildrenOfProjectionSurface, + RenderNodeOp* opState, + std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface) { mProjectedNodes.clear(); if (mDisplayList == nullptr || mDisplayList->isEmpty()) return; @@ -748,10 +570,10 @@ void RenderNode::computeOrderingImpl( const bool isProjectionReceiver = mDisplayList->projectionReceiveIndex >= 0; bool haveAppliedPropertiesToProjection = false; for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) { - renderNodeOp_t* childOp = mDisplayList->getChildren()[i]; + RenderNodeOp* childOp = mDisplayList->getChildren()[i]; RenderNode* child = childOp->renderNode; - std::vector<renderNodeOp_t*>* projectionChildren = nullptr; + std::vector<RenderNodeOp*>* projectionChildren = nullptr; const mat4* projectionTransform = nullptr; if (isProjectionReceiver && !child->properties().getProjectBackwards()) { // if receiving projections, collect projecting descendant @@ -774,372 +596,5 @@ void RenderNode::computeOrderingImpl( } } -class DeferOperationHandler { -public: - DeferOperationHandler(DeferStateStruct& deferStruct, int level) - : mDeferStruct(deferStruct), mLevel(level) {} - inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { - operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds); - } - inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); } - inline void startMark(const char* name) {} // do nothing - inline void endMark() {} - inline int level() { return mLevel; } - inline int replayFlags() { return mDeferStruct.mReplayFlags; } - inline SkPath* allocPathForFrame() { return mDeferStruct.allocPathForFrame(); } - -private: - DeferStateStruct& mDeferStruct; - const int mLevel; -}; - -void RenderNode::defer(DeferStateStruct& deferStruct, const int level) { - DeferOperationHandler handler(deferStruct, level); - issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler); -} - -class ReplayOperationHandler { -public: - ReplayOperationHandler(ReplayStateStruct& replayStruct, int level) - : mReplayStruct(replayStruct), mLevel(level) {} - inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { -#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS - mReplayStruct.mRenderer.eventMark(operation->name()); -#endif - operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds); - } - inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); } - inline void startMark(const char* name) { - mReplayStruct.mRenderer.startMark(name); - } - inline void endMark() { - mReplayStruct.mRenderer.endMark(); - } - inline int level() { return mLevel; } - inline int replayFlags() { return mReplayStruct.mReplayFlags; } - inline SkPath* allocPathForFrame() { return mReplayStruct.allocPathForFrame(); } - -private: - ReplayStateStruct& mReplayStruct; - const int mLevel; -}; - -void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) { - ReplayOperationHandler handler(replayStruct, level); - issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler); -} - -void RenderNode::buildZSortedChildList(const DisplayList::Chunk& chunk, - std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) { -#if !HWUI_NEW_OPS - if (chunk.beginChildIndex == chunk.endChildIndex) return; - - for (unsigned int i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) { - DrawRenderNodeOp* childOp = mDisplayList->getChildren()[i]; - RenderNode* child = childOp->renderNode; - float childZ = child->properties().getZ(); - - if (!MathUtils::isZero(childZ) && chunk.reorderChildren) { - zTranslatedNodes.push_back(ZDrawRenderNodeOpPair(childZ, childOp)); - childOp->skipInOrderDraw = true; - } else if (!child->properties().getProjectBackwards()) { - // regular, in order drawing DisplayList - childOp->skipInOrderDraw = false; - } - } - - // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order) - std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end()); -#endif -} - -template <class T> -void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) { - if (properties().getAlpha() <= 0.0f - || properties().getOutline().getAlpha() <= 0.0f - || !properties().getOutline().getPath() - || properties().getScaleX() == 0 - || properties().getScaleY() == 0) { - // no shadow to draw - return; - } - - mat4 shadowMatrixXY(transformFromParent); - applyViewPropertyTransforms(shadowMatrixXY); - - // Z matrix needs actual 3d transformation, so mapped z values will be correct - mat4 shadowMatrixZ(transformFromParent); - applyViewPropertyTransforms(shadowMatrixZ, true); - - const SkPath* casterOutlinePath = properties().getOutline().getPath(); - const SkPath* revealClipPath = properties().getRevealClip().getPath(); - if (revealClipPath && revealClipPath->isEmpty()) return; - - float casterAlpha = properties().getAlpha() * properties().getOutline().getAlpha(); - - - // holds temporary SkPath to store the result of intersections - SkPath* frameAllocatedPath = nullptr; - const SkPath* outlinePath = casterOutlinePath; - - // intersect the outline with the reveal clip, if present - if (revealClipPath) { - frameAllocatedPath = handler.allocPathForFrame(); - - Op(*outlinePath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath); - outlinePath = frameAllocatedPath; - } - - // intersect the outline with the clipBounds, if present - if (properties().getClippingFlags() & CLIP_TO_CLIP_BOUNDS) { - if (!frameAllocatedPath) { - frameAllocatedPath = handler.allocPathForFrame(); - } - - Rect clipBounds; - properties().getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds); - SkPath clipBoundsPath; - clipBoundsPath.addRect(clipBounds.left, clipBounds.top, - clipBounds.right, clipBounds.bottom); - - Op(*outlinePath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath); - outlinePath = frameAllocatedPath; - } - - DisplayListOp* shadowOp = new (handler.allocator()) DrawShadowOp( - shadowMatrixXY, shadowMatrixZ, casterAlpha, outlinePath); - handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds()); -} - -#define SHADOW_DELTA 0.1f - -template <class T> -void RenderNode::issueOperationsOf3dChildren(ChildrenSelectMode mode, - const Matrix4& initialTransform, const std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes, - OpenGLRenderer& renderer, T& handler) { - const int size = zTranslatedNodes.size(); - if (size == 0 - || (mode == ChildrenSelectMode::NegativeZChildren && zTranslatedNodes[0].key > 0.0f) - || (mode == ChildrenSelectMode::PositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) { - // no 3d children to draw - return; - } - - // Apply the base transform of the parent of the 3d children. This isolates - // 3d children of the current chunk from transformations made in previous chunks. - int rootRestoreTo = renderer.save(SaveFlags::Matrix); - renderer.setGlobalMatrix(initialTransform); - - /** - * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters - * with very similar Z heights to draw together. - * - * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are - * underneath both, and neither's shadow is drawn on top of the other. - */ - const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); - size_t drawIndex, shadowIndex, endIndex; - if (mode == ChildrenSelectMode::NegativeZChildren) { - drawIndex = 0; - endIndex = nonNegativeIndex; - shadowIndex = endIndex; // draw no shadows - } else { - drawIndex = nonNegativeIndex; - endIndex = size; - shadowIndex = drawIndex; // potentially draw shadow for each pos Z child - } - - DISPLAY_LIST_LOGD("%*s%d %s 3d children:", (handler.level() + 1) * 2, "", - endIndex - drawIndex, mode == kNegativeZChildren ? "negative" : "positive"); - - float lastCasterZ = 0.0f; - while (shadowIndex < endIndex || drawIndex < endIndex) { - if (shadowIndex < endIndex) { - DrawRenderNodeOp* casterOp = zTranslatedNodes[shadowIndex].value; - RenderNode* caster = casterOp->renderNode; - const float casterZ = zTranslatedNodes[shadowIndex].key; - // attempt to render the shadow if the caster about to be drawn is its caster, - // OR if its caster's Z value is similar to the previous potential caster - if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) { - caster->issueDrawShadowOperation(casterOp->localMatrix, handler); - - lastCasterZ = casterZ; // must do this even if current caster not casting a shadow - shadowIndex++; - continue; - } - } - - // only the actual child DL draw needs to be in save/restore, - // since it modifies the renderer's matrix - int restoreTo = renderer.save(SaveFlags::Matrix); - - DrawRenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; - - renderer.concatMatrix(childOp->localMatrix); - childOp->skipInOrderDraw = false; // this is horrible, I'm so sorry everyone - handler(childOp, renderer.getSaveCount() - 1, properties().getClipToBounds()); - childOp->skipInOrderDraw = true; - - renderer.restoreToCount(restoreTo); - drawIndex++; - } - renderer.restoreToCount(rootRestoreTo); -} - -template <class T> -void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) { - DISPLAY_LIST_LOGD("%*s%d projected children:", (handler.level() + 1) * 2, "", mProjectedNodes.size()); - const SkPath* projectionReceiverOutline = properties().getOutline().getPath(); - int restoreTo = renderer.getSaveCount(); - - LinearAllocator& alloc = handler.allocator(); - handler(new (alloc) SaveOp(SaveFlags::MatrixClip), - PROPERTY_SAVECOUNT, properties().getClipToBounds()); - - // Transform renderer to match background we're projecting onto - // (by offsetting canvas by translationX/Y of background rendernode, since only those are set) - const DisplayListOp* op = -#if HWUI_NEW_OPS - nullptr; - LOG_ALWAYS_FATAL("unsupported"); -#else - (mDisplayList->getOps()[mDisplayList->projectionReceiveIndex]); -#endif - const DrawRenderNodeOp* backgroundOp = reinterpret_cast<const DrawRenderNodeOp*>(op); - const RenderProperties& backgroundProps = backgroundOp->renderNode->properties(); - renderer.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY()); - - // If the projection receiver has an outline, we mask projected content to it - // (which we know, apriori, are all tessellated paths) - renderer.setProjectionPathMask(alloc, projectionReceiverOutline); - - // draw projected nodes - for (size_t i = 0; i < mProjectedNodes.size(); i++) { - renderNodeOp_t* childOp = mProjectedNodes[i]; - - // matrix save, concat, and restore can be done safely without allocating operations - int restoreTo = renderer.save(SaveFlags::Matrix); - renderer.concatMatrix(childOp->transformFromCompositingAncestor); - childOp->skipInOrderDraw = false; // this is horrible, I'm so sorry everyone - handler(childOp, renderer.getSaveCount() - 1, properties().getClipToBounds()); - childOp->skipInOrderDraw = true; - renderer.restoreToCount(restoreTo); - } - - handler(new (alloc) RestoreToCountOp(restoreTo), - PROPERTY_SAVECOUNT, properties().getClipToBounds()); -} - -/** - * This function serves both defer and replay modes, and will organize the displayList's component - * operations for a single frame: - * - * Every 'simple' state operation that affects just the matrix and alpha (or other factors of - * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom - * defer logic) and operations in displayListOps are issued through the 'handler' which handles the - * defer vs replay logic, per operation - */ -template <class T> -void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { - if (mDisplayList->isEmpty()) { - DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", handler.level() * 2, "", - this, getName()); - return; - } - -#if HWUI_NEW_OPS - const bool drawLayer = false; -#else - const bool drawLayer = (mLayer && (&renderer != mLayer->renderer.get())); -#endif - // If we are updating the contents of mLayer, we don't want to apply any of - // the RenderNode's properties to this issueOperations pass. Those will all - // be applied when the layer is drawn, aka when this is true. - const bool useViewProperties = (!mLayer || drawLayer); - if (useViewProperties) { - const Outline& outline = properties().getOutline(); - if (properties().getAlpha() <= 0 - || (outline.getShouldClip() && outline.isEmpty()) - || properties().getScaleX() == 0 - || properties().getScaleY() == 0) { - DISPLAY_LIST_LOGD("%*sRejected display list (%p, %s)", handler.level() * 2, "", - this, getName()); - return; - } - } - - handler.startMark(getName()); - -#if DEBUG_DISPLAY_LIST - const Rect& clipRect = renderer.getLocalClipBounds(); - DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f", - handler.level() * 2, "", this, getName(), - clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); -#endif - - LinearAllocator& alloc = handler.allocator(); - int restoreTo = renderer.getSaveCount(); - handler(new (alloc) SaveOp(SaveFlags::MatrixClip), - PROPERTY_SAVECOUNT, properties().getClipToBounds()); - - DISPLAY_LIST_LOGD("%*sSave %d %d", (handler.level() + 1) * 2, "", - SaveFlags::MatrixClip, restoreTo); - - if (useViewProperties) { - setViewProperties<T>(renderer, handler); - } - -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("legacy op traversal not supported"); -#else - bool quickRejected = properties().getClipToBounds() - && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight()); - if (!quickRejected) { - Matrix4 initialTransform(*(renderer.currentTransform())); - renderer.setBaseTransform(initialTransform); - - if (drawLayer) { - handler(new (alloc) DrawLayerOp(mLayer), - renderer.getSaveCount() - 1, properties().getClipToBounds()); - } else { - const int saveCountOffset = renderer.getSaveCount() - 1; - const int projectionReceiveIndex = mDisplayList->projectionReceiveIndex; - for (size_t chunkIndex = 0; chunkIndex < mDisplayList->getChunks().size(); chunkIndex++) { - const DisplayList::Chunk& chunk = mDisplayList->getChunks()[chunkIndex]; - - std::vector<ZDrawRenderNodeOpPair> zTranslatedNodes; - buildZSortedChildList(chunk, zTranslatedNodes); - - issueOperationsOf3dChildren(ChildrenSelectMode::NegativeZChildren, - initialTransform, zTranslatedNodes, renderer, handler); - - for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { - DisplayListOp *op = mDisplayList->getOps()[opIndex]; -#if DEBUG_DISPLAY_LIST - op->output(handler.level() + 1); -#endif - handler(op, saveCountOffset, properties().getClipToBounds()); - - if (CC_UNLIKELY(!mProjectedNodes.empty() && projectionReceiveIndex >= 0 && - opIndex == static_cast<size_t>(projectionReceiveIndex))) { - issueOperationsOfProjectedChildren(renderer, handler); - } - } - - issueOperationsOf3dChildren(ChildrenSelectMode::PositiveZChildren, - initialTransform, zTranslatedNodes, renderer, handler); - } - } - } -#endif - - DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (handler.level() + 1) * 2, "", restoreTo); - handler(new (alloc) RestoreToCountOp(restoreTo), - PROPERTY_SAVECOUNT, properties().getClipToBounds()); - - DISPLAY_LIST_LOGD("%*sDone (%p, %s)", handler.level() * 2, "", this, getName()); - handler.endMark(); -} - } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index f9735a231d7a..ee045aaae0a4 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef RENDERNODE_H -#define RENDERNODE_H + +#pragma once #include <SkCamera.h> #include <SkMatrix.h> @@ -44,29 +44,13 @@ namespace android { namespace uirenderer { class CanvasState; -class DisplayListCanvas; class DisplayListOp; -class OpenGLRenderer; -class Rect; -class SkiaShader; - -#if HWUI_NEW_OPS class FrameBuilder; class OffscreenBuffer; +class Rect; +class SkiaShader; struct RenderNodeOp; -typedef OffscreenBuffer layer_t; -typedef RenderNodeOp renderNodeOp_t; -#else -class Layer; -typedef Layer layer_t; -typedef DrawRenderNodeOp renderNodeOp_t; -#endif - -class ClipRectOp; -class DrawRenderNodeOp; -class SaveLayerOp; -class SaveOp; -class RestoreToCountOp; + class TreeInfo; class TreeObserver; @@ -78,9 +62,8 @@ class RenderNode; * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties. * * Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording - * functionality is split between DisplayListCanvas (which manages the recording), DisplayList - * (which holds the actual data), and DisplayList (which holds properties and performs playback onto - * a renderer). + * functionality is split between RecordingCanvas (which manages the recording), DisplayList + * (which holds the actual data), and RenderNode (which holds properties used for render playback). * * Note that DisplayList is swapped out from beneath an individual RenderNode when a view's * recorded stream of canvas operations is refreshed. The RenderNode (and its properties) stay @@ -115,20 +98,11 @@ public: kReplayFlag_ClipChildren = 0x1 }; - void debugDumpLayers(const char* prefix); - ANDROID_API void setStagingDisplayList(DisplayList* newData, TreeObserver* observer); void computeOrdering(); - void defer(DeferStateStruct& deferStruct, const int level); - void replay(ReplayStateStruct& replayStruct, const int level); - -#if HWUI_NEW_OPS ANDROID_API void output(uint32_t level = 0, const char* label = "Root"); -#else - ANDROID_API void output(uint32_t level = 1); -#endif ANDROID_API int getDebugSize(); void copyTo(proto::RenderNode* node); @@ -223,10 +197,8 @@ public: const DisplayList* getDisplayList() const { return mDisplayList; } -#if HWUI_NEW_OPS OffscreenBuffer* getLayer() const { return mLayer; } OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh... -#endif // Note: The position callbacks are relying on the listener using // the frameNumber to appropriately batch/synchronize these transactions. @@ -257,63 +229,10 @@ public: } private: - typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair; - - static size_t findNonNegativeIndex(const std::vector<ZDrawRenderNodeOpPair>& nodes) { - for (size_t i = 0; i < nodes.size(); i++) { - if (nodes[i].key >= 0.0f) return i; - } - return nodes.size(); - } - - enum class ChildrenSelectMode { - NegativeZChildren, - PositiveZChildren - }; - - void computeOrderingImpl(renderNodeOp_t* opState, - std::vector<renderNodeOp_t*>* compositedChildrenOfProjectionSurface, + void computeOrderingImpl(RenderNodeOp* opState, + std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface); - template <class T> - inline void setViewProperties(OpenGLRenderer& renderer, T& handler); - - void buildZSortedChildList(const DisplayList::Chunk& chunk, - std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes); - - template<class T> - inline void issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler); - - template <class T> - inline void issueOperationsOf3dChildren(ChildrenSelectMode mode, - const Matrix4& initialTransform, const std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes, - OpenGLRenderer& renderer, T& handler); - - template <class T> - inline void issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler); - - /** - * Issue the RenderNode's operations into a handler, recursing for subtrees through - * DrawRenderNodeOp's defer() or replay() methods - */ - template <class T> - inline void issueOperations(OpenGLRenderer& renderer, T& handler); - - class TextContainer { - public: - size_t length() const { - return mByteLength; - } - - const char* text() const { - return (const char*) mText; - } - - size_t mByteLength; - const char* mText; - }; - - void syncProperties(); void syncDisplayList(TreeInfo* info); @@ -321,9 +240,6 @@ private: void pushStagingPropertiesChanges(TreeInfo& info); void pushStagingDisplayListChanges(TreeInfo& info); void prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayList* subtree); -#if !HWUI_NEW_OPS - void applyLayerPropertiesToLayer(TreeInfo& info); -#endif void prepareLayer(TreeInfo& info, uint32_t dirtyMask); void pushLayerUpdate(TreeInfo& info); void deleteDisplayList(TreeObserver* observer, TreeInfo* info = nullptr); @@ -349,14 +265,14 @@ private: // Owned by RT. Lifecycle is managed by prepareTree(), with the exception // being in ~RenderNode() which may happen on any thread. - layer_t* mLayer = nullptr; + OffscreenBuffer* mLayer = nullptr; /** * Draw time state - these properties are only set and used during rendering */ // for projection surfaces, contains a list of all children items - std::vector<renderNodeOp_t*> mProjectedNodes; + std::vector<RenderNodeOp*> mProjectedNodes; // How many references our parent(s) have to us. Typically this should alternate // between 2 and 1 (when a staging push happens we inc first then dec) @@ -371,5 +287,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* RENDERNODE_H */ diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp index 5ebf5458da18..7e3cad4ca9d0 100644 --- a/libs/hwui/RenderProperties.cpp +++ b/libs/hwui/RenderProperties.cpp @@ -24,7 +24,6 @@ #include <SkPathOps.h> #include "Matrix.h" -#include "OpenGLRenderer.h" #include "hwui/Canvas.h" #include "utils/MathUtils.h" diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 6a6e8dbb3fcd..00494a12b808 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef RENDERNODEPROPERTIES_H -#define RENDERNODEPROPERTIES_H + +#pragma once #include "Caches.h" #include "DeviceInfo.h" @@ -22,6 +22,7 @@ #include "RevealClip.h" #include "Outline.h" #include "utils/MathUtils.h" +#include "utils/PaintUtils.h" #include <SkCamera.h> #include <SkMatrix.h> @@ -678,5 +679,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* RENDERNODEPROPERTIES_H */ diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 0693804d5770..600707ab86ac 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -29,7 +29,6 @@ #include <SkImage.h> #include <SkShader.h> #include <SkTArray.h> -#include <SkTLazy.h> #include <SkTemplates.h> #include "VectorDrawable.h" @@ -352,13 +351,12 @@ int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, int alpha, SaveFlags::Flags flags) { - SkTLazy<SkPaint> alphaPaint; if (static_cast<unsigned>(alpha) < 0xFF) { - alphaPaint.init()->setAlpha(alpha); + SkPaint alphaPaint; + alphaPaint.setAlpha(alpha); + return this->saveLayer(left, top, right, bottom, &alphaPaint, flags); } - - return this->saveLayer(left, top, right, bottom, alphaPaint.getMaybeNull(), - flags); + return this->saveLayer(left, top, right, bottom, nullptr, flags); } // ---------------------------------------------------------------------------- diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp index 9df32b28bf3b..f264a3597ef2 100644 --- a/libs/hwui/SkiaCanvasProxy.cpp +++ b/libs/hwui/SkiaCanvasProxy.cpp @@ -23,6 +23,7 @@ #include <SkPixelRef.h> #include <SkRect.h> #include <SkRRect.h> +#include <SkSurface.h> #include <memory> @@ -153,7 +154,7 @@ void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkP mCanvas->drawVertices(mode, floatCount, vArray, tArray, cArray, indices, indexCount, paint); } -SkSurface* SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) { +sk_sp<SkSurface> SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) { SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported"); return NULL; } diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h index 973c55fe2236..d1c9c6b2ad70 100644 --- a/libs/hwui/SkiaCanvasProxy.h +++ b/libs/hwui/SkiaCanvasProxy.h @@ -44,7 +44,7 @@ public: protected: - virtual SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; + virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; virtual void willSave() override; virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp index 2c9c9d90f686..21c26f7a1d44 100644 --- a/libs/hwui/Snapshot.cpp +++ b/libs/hwui/Snapshot.cpp @@ -30,14 +30,11 @@ Snapshot::Snapshot() , previous(nullptr) , layer(nullptr) , fbo(0) - , invisible(false) - , empty(false) , alpha(1.0f) , roundRectClipState(nullptr) , projectionPathMask(nullptr) , mClipArea(&mClipAreaRoot) { transform = &mTransformRoot; - region = nullptr; } /** @@ -49,8 +46,6 @@ Snapshot::Snapshot(Snapshot* s, int saveFlags) , previous(s) , layer(s->layer) , fbo(s->fbo) - , invisible(s->invisible) - , empty(false) , alpha(s->alpha) , roundRectClipState(s->roundRectClipState) , projectionPathMask(s->projectionPathMask) @@ -70,13 +65,6 @@ Snapshot::Snapshot(Snapshot* s, int saveFlags) } else { mClipArea = s->mClipArea; } - - if (s->flags & Snapshot::kFlagFboTarget) { - flags |= Snapshot::kFlagFboTarget; - region = s->region; - } else { - region = nullptr; - } } /////////////////////////////////////////////////////////////////////////////// @@ -126,58 +114,6 @@ void Snapshot::resetClip(float left, float top, float right, float bottom) { } /////////////////////////////////////////////////////////////////////////////// -// Transforms -/////////////////////////////////////////////////////////////////////////////// - -void Snapshot::resetTransform(float x, float y, float z) { -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("not supported - light center managed differently"); -#else - // before resetting, map current light pos with inverse of current transform - Vector3 center = mRelativeLightCenter; - mat4 inverse; - inverse.loadInverse(*transform); - inverse.mapPoint3d(center); - mRelativeLightCenter = center; - - transform = &mTransformRoot; - transform->loadTranslate(x, y, z); -#endif -} - -void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const { -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("not supported - not needed by new ops"); -#else - // build (reverse ordered) list of the stack of snapshots, terminated with a NULL - Vector<const Snapshot*> snapshotList; - snapshotList.push(nullptr); - const Snapshot* current = this; - do { - snapshotList.push(current); - current = current->previous; - } while (current); - - // traverse the list, adding in each transform that contributes to the total transform - outTransform->loadIdentity(); - for (size_t i = snapshotList.size() - 1; i > 0; i--) { - // iterate down the stack - const Snapshot* current = snapshotList[i]; - const Snapshot* next = snapshotList[i - 1]; - if (current->flags & kFlagIsFboLayer) { - // if we've hit a layer, translate by the layer's draw offset - outTransform->translate(current->layer->layer.left, current->layer->layer.top); - } - if (!next || (next->flags & kFlagIsFboLayer)) { - // if this snapshot is last, or if this snapshot is last before an - // FBO layer (which reset the transform), apply it - outTransform->multiply(*(current->transform)); - } - } -#endif -} - -/////////////////////////////////////////////////////////////////////////////// // Clipping round rect /////////////////////////////////////////////////////////////////////////////// @@ -226,20 +162,8 @@ void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& boun roundRectClipState = state; } -void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) { -#if HWUI_NEW_OPS - // TODO: remove allocator param for HWUI_NEW_OPS +void Snapshot::setProjectionPathMask(const SkPath* path) { projectionPathMask = path; -#else - if (path) { - ProjectionPathMask* mask = new (allocator) ProjectionPathMask; - mask->projectionMask = path; - buildScreenSpaceTransform(&(mask->projectionMaskTransform)); - projectionPathMask = mask; - } else { - projectionPathMask = nullptr; - } -#endif } static Snapshot* getClipRoot(Snapshot* target) { @@ -273,13 +197,9 @@ void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) // Queries /////////////////////////////////////////////////////////////////////////////// -bool Snapshot::isIgnored() const { - return invisible || empty; -} - void Snapshot::dump() const { - ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d", - this, flags, previous, getViewportHeight(), isIgnored(), !mClipArea->isSimple()); + ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d", + this, flags, previous, getViewportHeight(), !mClipArea->isSimple()); const Rect& clipRect(mClipArea->getClipRect()); ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d", clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple()); diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index d8f926ef3925..4ab58302df8f 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_SNAPSHOT_H -#define ANDROID_HWUI_SNAPSHOT_H +#pragma once #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> @@ -63,18 +62,6 @@ public: float radius; }; -// TODO: remove for HWUI_NEW_OPS -class ProjectionPathMask { -public: - static void* operator new(size_t size) = delete; - static void* operator new(size_t size, LinearAllocator& allocator) { - return allocator.alloc<ProjectionPathMask>(size); - } - - const SkPath* projectionMask; - Matrix4 projectionMaskTransform; -}; - /** * A snapshot holds information about the current state of the rendering * surface. A snapshot is usually created whenever the user calls save() @@ -113,11 +100,6 @@ public: * restored when this snapshot is restored. */ kFlagIsFboLayer = 0x4, - /** - * Indicates that this snapshot or an ancestor snapshot is - * an FBO layer. - */ - kFlagFboTarget = 0x8, // TODO: remove for HWUI_NEW_OPS }; /** @@ -179,11 +161,6 @@ public: */ void resetClip(float left, float top, float right, float bottom); - /** - * Resets the current transform to a pure 3D translation. - */ - void resetTransform(float x, float y, float z); - void initializeViewport(int width, int height) { mViewportData.initialize(width, height); mClipAreaRoot.setViewportDimensions(width, height); @@ -207,13 +184,7 @@ public: /** * Sets (and replaces) the current projection mask */ - void setProjectionPathMask(LinearAllocator& allocator, const SkPath* path); - - /** - * Indicates whether this snapshot should be ignored. A snapshot - * is typically ignored if its layer is invisible or empty. - */ - bool isIgnored() const; + void setProjectionPathMask(const SkPath* path); /** * Indicates whether the current transform has perspective components. @@ -221,13 +192,6 @@ public: bool hasPerspectiveTransform() const; /** - * Fills outTransform with the current, total transform to screen space, - * across layer boundaries. - */ - // TODO: remove for HWUI_NEW_OPS - void buildScreenSpaceTransform(Matrix4* outTransform) const; - - /** * Dirty flags. */ int flags; @@ -251,19 +215,6 @@ public: GLuint fbo; /** - * Indicates that this snapshot is invisible and nothing should be drawn - * inside it. This flag is set only when the layer clips drawing to its - * bounds and is passed to subsequent snapshots. - */ - bool invisible; - - /** - * If set to true, the layer will not be composited. This is similar to - * invisible but this flag is not passed to subsequent snapshots. - */ - bool empty; - - /** * Local transformation. Holds the current translation, scale and * rotation values. * @@ -273,14 +224,6 @@ public: mat4* transform; /** - * The ancestor layer's dirty region. - * - * This is a reference to a region owned by a layer. This pointer must - * not be freed. - */ - Region* region; - - /** * Current alpha value. This value is 1 by default, but may be set by a DisplayList which * has translucent rendering in a non-overlapping View. This value will be used by * the renderer to set the alpha in the current color being used for ensuing drawing @@ -302,11 +245,7 @@ public: /** * Current projection masking path - used exclusively to mask projected, tessellated circles. */ -#if HWUI_NEW_OPS const SkPath* projectionPathMask; -#else - const ProjectionPathMask* projectionPathMask; -#endif void dump() const; @@ -345,5 +284,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_SNAPSHOT_H diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp index d9e811684610..91e7ac39af90 100644 --- a/libs/hwui/TessellationCache.cpp +++ b/libs/hwui/TessellationCache.cpp @@ -18,7 +18,6 @@ #include <utils/Trace.h> #include "Caches.h" -#include "OpenGLRenderer.h" #include "PathTessellator.h" #include "ShadowTessellator.h" #include "TessellationCache.h" @@ -369,21 +368,6 @@ void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect mShadowCache.put(key, task.get()); } -void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip, - bool opaque, const SkPath* casterPerimeter, - const Matrix4* transformXY, const Matrix4* transformZ, - const Vector3& lightCenter, float lightRadius, vertexBuffer_pair_t& outBuffers) { - ShadowDescription key(casterPerimeter, drawTransform); - ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key)); - if (!task) { - precacheShadows(drawTransform, localClip, opaque, casterPerimeter, - transformXY, transformZ, lightCenter, lightRadius); - task = static_cast<ShadowTask*>(mShadowCache.get(key)); - } - LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached"); - outBuffers = task->getResult(); -} - sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask( const Matrix4* drawTransform, const Rect& localClip, bool opaque, const SkPath* casterPerimeter, diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h index 6141b4ef63d7..ccad1b7bd415 100644 --- a/libs/hwui/TessellationCache.h +++ b/libs/hwui/TessellationCache.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_TESSELLATION_CACHE_H -#define ANDROID_HWUI_TESSELLATION_CACHE_H +#pragma once #include "Debug.h" #include "Matrix.h" @@ -161,17 +160,6 @@ public: const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry); - // TODO: delete these when switching to HWUI_NEW_OPS - void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, - bool opaque, const SkPath* casterPerimeter, - const Matrix4* transformXY, const Matrix4* transformZ, - const Vector3& lightCenter, float lightRadius); - void getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip, - bool opaque, const SkPath* casterPerimeter, - const Matrix4* transformXY, const Matrix4* transformZ, - const Vector3& lightCenter, float lightRadius, - vertexBuffer_pair_t& outBuffers); - sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque, const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ, @@ -184,6 +172,11 @@ private: typedef VertexBuffer* (*Tessellator)(const Description&); + void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, + bool opaque, const SkPath* casterPerimeter, + const Matrix4* transformXY, const Matrix4* transformZ, + const Vector3& lightCenter, float lightRadius); + Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, float height); Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint, @@ -232,5 +225,3 @@ void tessellateShadows( }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_PATH_CACHE_H diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index ac2bdccf5255..2087fca205da 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef TREEINFO_H -#define TREEINFO_H + +#pragma once #include "utils/Macros.h" @@ -31,7 +31,6 @@ class CanvasContext; class DamageAccumulator; class LayerUpdateQueue; -class OpenGLRenderer; class RenderNode; class RenderState; @@ -89,13 +88,7 @@ public: // Must not be null during actual usage DamageAccumulator* damageAccumulator = nullptr; -#if HWUI_NEW_OPS LayerUpdateQueue* layerUpdateQueue = nullptr; -#else - // The renderer that will be drawing the next frame. Use this to push any - // layer updates or similar. May be NULL. - OpenGLRenderer* renderer = nullptr; -#endif ErrorHandler* errorHandler = nullptr; // Optional, may be nullptr. Used to allow things to observe interesting @@ -128,5 +121,3 @@ public: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* TREEINFO_H */ diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h index e67dfdd15703..940b1ca84dc1 100644 --- a/libs/hwui/VectorDrawable.h +++ b/libs/hwui/VectorDrawable.h @@ -39,6 +39,13 @@ namespace android { namespace uirenderer { +// Debug +#if DEBUG_VECTOR_DRAWABLE + #define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__) +#else + #define VECTOR_DRAWABLE_LOGD(...) +#endif + namespace VectorDrawable { #define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false) #define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false) diff --git a/libs/hwui/debug/DefaultGlesDriver.cpp b/libs/hwui/debug/DefaultGlesDriver.cpp new file mode 100644 index 000000000000..4515ec1f25a5 --- /dev/null +++ b/libs/hwui/debug/DefaultGlesDriver.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DefaultGlesDriver.h" + +#include "gles_undefine.h" + +#include <EGL/egl.h> + +namespace android { +namespace uirenderer { +namespace debug { + +// Generate the proxy +#define API_ENTRY(x) DefaultGlesDriver::x##_ +#define CALL_GL_API(x, ...) x(__VA_ARGS__); +#define CALL_GL_API_RETURN(x, ...) return x(__VA_ARGS__); + +#include "gles_stubs.in" + +#undef API_ENTRY +#undef CALL_GL_API +#undef CALL_GL_API_RETURN + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/DefaultGlesDriver.h b/libs/hwui/debug/DefaultGlesDriver.h new file mode 100644 index 000000000000..3eab97077004 --- /dev/null +++ b/libs/hwui/debug/DefaultGlesDriver.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "GlesDriver.h" + +namespace android { +namespace uirenderer { +namespace debug { + +class DefaultGlesDriver : public GlesDriver { +public: +#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override; + #include "gles_decls.in" +#undef GL_ENTRY + +}; + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/FatalBaseDriver.cpp b/libs/hwui/debug/FatalBaseDriver.cpp new file mode 100644 index 000000000000..99ac358163ff --- /dev/null +++ b/libs/hwui/debug/FatalBaseDriver.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FatalBaseDriver.h" + +#include <cutils/log.h> + +namespace android { +namespace uirenderer { +namespace debug { + +// Generate the proxy +#define API_ENTRY(x) FatalBaseDriver::x##_ +#define CALL_GL_API(x, ...) LOG_ALWAYS_FATAL("Not Implemented"); +#define CALL_GL_API_RETURN(x, ...) \ + LOG_ALWAYS_FATAL("Not Implemented"); \ + return static_cast<decltype(x(__VA_ARGS__))>(0); + +#include "gles_stubs.in" + +#undef API_ENTRY +#undef CALL_GL_API +#undef CALL_GL_API_RETURN + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/FatalBaseDriver.h b/libs/hwui/debug/FatalBaseDriver.h new file mode 100644 index 000000000000..76c30e90bd39 --- /dev/null +++ b/libs/hwui/debug/FatalBaseDriver.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "GlesDriver.h" + +namespace android { +namespace uirenderer { +namespace debug { + +// A base driver that implements all the pure virtuals in the form of +// LOG_ALWAYS_FATALS. Suitable for selective-override implementations +// where only a known subset of methods need to be overridden +class FatalBaseDriver : public GlesDriver { +public: +#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override; + #include "gles_decls.in" +#undef GL_ENTRY +}; + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/GlesDriver.cpp b/libs/hwui/debug/GlesDriver.cpp new file mode 100644 index 000000000000..b8ef639074de --- /dev/null +++ b/libs/hwui/debug/GlesDriver.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "GlesDriver.h" +#include "DefaultGlesDriver.h" +#include "GlesErrorCheckWrapper.h" + +namespace android { +namespace uirenderer { +namespace debug { + +static DefaultGlesDriver sDefaultDriver; + +static std::unique_ptr<GlesDriver> sGlesDriver(new GlesErrorCheckWrapper(sDefaultDriver)); + +GlesDriver* GlesDriver::get() { + return sGlesDriver.get(); +} + +std::unique_ptr<GlesDriver> GlesDriver::replace(std::unique_ptr<GlesDriver>&& driver) { + std::unique_ptr<GlesDriver> ret = std::move(sGlesDriver); + sGlesDriver = std::move(driver); + return ret; +} + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/GlesDriver.h b/libs/hwui/debug/GlesDriver.h new file mode 100644 index 000000000000..ca6f4b628eab --- /dev/null +++ b/libs/hwui/debug/GlesDriver.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef HWUI_GLES_WRAP_ENABLED +#error Wrapping wasn't enabled, can't use this! +#endif + +#include <GLES/gl.h> +#include <GLES/glext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <GLES3/gl3.h> +#include <GLES3/gl31.h> +#include <GLES3/gl32.h> + +#include <memory> + +namespace android { +namespace uirenderer { +namespace debug { + +// All the gl methods on GlesDriver have a trailing underscore +// This is to avoid collision with gles_redefine/gles_undefine +class GlesDriver { +public: + virtual ~GlesDriver() {} + +#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) = 0; + #include "gles_decls.in" +#undef GL_ENTRY + + static GlesDriver* get(); + static std::unique_ptr<GlesDriver> replace(std::unique_ptr<GlesDriver>&& driver); +}; + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/GlesErrorCheckWrapper.cpp b/libs/hwui/debug/GlesErrorCheckWrapper.cpp new file mode 100644 index 000000000000..8366387b6d98 --- /dev/null +++ b/libs/hwui/debug/GlesErrorCheckWrapper.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "GlesErrorCheckWrapper.h" + +#include <cutils/log.h> + +namespace android { +namespace uirenderer { +namespace debug { + +void GlesErrorCheckWrapper::assertNoErrors(const char* apicall) { + GLenum status = GL_NO_ERROR; + GLenum lastError = GL_NO_ERROR; + const char* lastErrorName = nullptr; + while ((status = mBase.glGetError_()) != GL_NO_ERROR) { + lastError = status; + switch (status) { + case GL_INVALID_ENUM: + ALOGE("GL error: GL_INVALID_ENUM"); + lastErrorName = "GL_INVALID_ENUM"; + break; + case GL_INVALID_VALUE: + ALOGE("GL error: GL_INVALID_VALUE"); + lastErrorName = "GL_INVALID_VALUE"; + break; + case GL_INVALID_OPERATION: + ALOGE("GL error: GL_INVALID_OPERATION"); + lastErrorName = "GL_INVALID_OPERATION"; + break; + case GL_OUT_OF_MEMORY: + ALOGE("GL error: Out of memory!"); + lastErrorName = "GL_OUT_OF_MEMORY"; + break; + default: + ALOGE("GL error: 0x%x", status); + lastErrorName = "UNKNOWN"; + } + } + LOG_ALWAYS_FATAL_IF(lastError != GL_NO_ERROR, + "%s error! %s (0x%x)", apicall, lastErrorName, lastError); +} + +#define API_ENTRY(x) GlesErrorCheckWrapper::x##_ +#define CALL_GL_API(x, ...) \ + mBase.x##_(__VA_ARGS__); assertNoErrors(#x) + +#define CALL_GL_API_RETURN(x, ...) \ + auto ret = mBase.x##_(__VA_ARGS__); \ + assertNoErrors(#x); \ + return ret + +#include "gles_stubs.in" + +#undef API_ENTRY +#undef CALL_GL_API +#undef CALL_GL_API_RETURN + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/GlesErrorCheckWrapper.h b/libs/hwui/debug/GlesErrorCheckWrapper.h new file mode 100644 index 000000000000..fd45fc0184a1 --- /dev/null +++ b/libs/hwui/debug/GlesErrorCheckWrapper.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "GlesDriver.h" + +namespace android { +namespace uirenderer { +namespace debug { + +class GlesErrorCheckWrapper : public GlesDriver { +public: + GlesErrorCheckWrapper(GlesDriver& base) : mBase(base) {} + +#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override; + #include "gles_decls.in" +#undef GL_ENTRY + +private: + void assertNoErrors(const char* apicall); + + GlesDriver& mBase; +}; + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/MockGlesDriver.h b/libs/hwui/debug/MockGlesDriver.h new file mode 100644 index 000000000000..e0bfc5780b21 --- /dev/null +++ b/libs/hwui/debug/MockGlesDriver.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "FatalBaseDriver.h" + +#include <gmock/gmock.h> + +namespace android { +namespace uirenderer { +namespace debug { + +class MockGlesDriver : public FatalBaseDriver { +public: + MOCK_METHOD2(glBindBuffer_, void(GLenum target, GLuint buffer)); + MOCK_METHOD4(glBufferData_, void(GLenum target, GLsizeiptr size, const void *data, GLenum usage)); + MOCK_METHOD2(glGenBuffers_, void(GLsizei n, GLuint *buffers)); +}; + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/NullGlesDriver.cpp b/libs/hwui/debug/NullGlesDriver.cpp new file mode 100644 index 000000000000..e9dbc7446f4e --- /dev/null +++ b/libs/hwui/debug/NullGlesDriver.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <debug/NullGlesDriver.h> + +namespace android { +namespace uirenderer { +namespace debug { + +struct { + GLboolean scissorEnabled; +} gState; + +static void nullglGenCommon(GLsizei n, GLuint *buffers) { + static GLuint nextId = 0; + int i; + for(i = 0; i < n; i++) { + buffers[i] = ++nextId; + } +} + +void NullGlesDriver::glGenBuffers_(GLsizei n, GLuint *buffers) { + nullglGenCommon(n, buffers); +} + +void NullGlesDriver::glGenFramebuffers_(GLsizei n, GLuint *framebuffers) { + nullglGenCommon(n, framebuffers); +} + +void NullGlesDriver::glGenRenderbuffers_(GLsizei n, GLuint *renderbuffers) { + nullglGenCommon(n, renderbuffers); +} + +void NullGlesDriver::glGenTextures_(GLsizei n, GLuint *textures) { + nullglGenCommon(n, textures); +} + +GLuint NullGlesDriver::glCreateProgram_(void) { + static GLuint nextProgram = 0; + return ++nextProgram; +} + +GLuint NullGlesDriver::glCreateShader_(GLenum type) { + static GLuint nextShader = 0; + return ++nextShader; +} + +void NullGlesDriver::glGetProgramiv_(GLuint program, GLenum pname, GLint *params) { + switch (pname) { + case GL_DELETE_STATUS: + case GL_LINK_STATUS: + case GL_VALIDATE_STATUS: + *params = GL_TRUE; + break; + case GL_INFO_LOG_LENGTH: + *params = 16; + break; + } +} + +void NullGlesDriver::glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { + *length = snprintf(infoLog, bufSize, "success"); + if (*length >= bufSize) { + *length = bufSize - 1; + } +} + +void NullGlesDriver::glGetShaderiv_(GLuint shader, GLenum pname, GLint *params) { + switch (pname) { + case GL_COMPILE_STATUS: + case GL_DELETE_STATUS: + *params = GL_TRUE; + } +} + +void NullGlesDriver::glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { + *length = snprintf(infoLog, bufSize, "success"); + if (*length >= bufSize) { + *length = bufSize - 1; + } +} + +void setBooleanState(GLenum cap, GLboolean value) { + switch (cap) { + case GL_SCISSOR_TEST: + gState.scissorEnabled = value; + break; + } +} + +void NullGlesDriver::glEnable_(GLenum cap) { + setBooleanState(cap, GL_TRUE); +} + +void NullGlesDriver::glDisable_(GLenum cap) { + setBooleanState(cap, GL_FALSE); +} + +GLboolean NullGlesDriver::glIsEnabled_(GLenum cap) { + switch (cap) { + case GL_SCISSOR_TEST: + return gState.scissorEnabled; + default: + return GL_FALSE; + } +} + +void NullGlesDriver::glGetIntegerv_(GLenum pname, GLint *data) { + switch (pname) { + case GL_MAX_TEXTURE_SIZE: + *data = 2048; + break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: + *data = 4; + break; + default: + *data = 0; + } +} + +GLenum NullGlesDriver::glCheckFramebufferStatus_(GLenum target) { + switch (target) { + case GL_FRAMEBUFFER: + return GL_FRAMEBUFFER_COMPLETE; + default: + return 0; // error case + } +} + +static const char* getString(GLenum name) { + switch (name) { + case GL_VENDOR: + return "android"; + case GL_RENDERER: + return "null"; + case GL_VERSION: + return "OpenGL ES 2.0 rev1"; + case GL_SHADING_LANGUAGE_VERSION: + return "OpenGL ES GLSL ES 2.0 rev1"; + case GL_EXTENSIONS: + default: + return ""; + } +} + +const GLubyte* NullGlesDriver::glGetString_(GLenum name) { + return (GLubyte*) getString(name); +} + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/NullGlesDriver.h b/libs/hwui/debug/NullGlesDriver.h new file mode 100644 index 000000000000..d73137983940 --- /dev/null +++ b/libs/hwui/debug/NullGlesDriver.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "FatalBaseDriver.h" + +namespace android { +namespace uirenderer { +namespace debug { + +class NullGlesDriver : public FatalBaseDriver { +public: + virtual void glGenBuffers_(GLsizei n, GLuint *buffers) override; + virtual void glGenFramebuffers_(GLsizei n, GLuint *framebuffers) override; + virtual void glGenRenderbuffers_(GLsizei n, GLuint *renderbuffers) override; + virtual void glGenTextures_(GLsizei n, GLuint *textures) override; + virtual GLuint glCreateProgram_(void) override; + virtual GLuint glCreateShader_(GLenum type) override; + virtual void glGetProgramiv_(GLuint program, GLenum pname, GLint *params) override; + virtual void glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) override; + virtual void glGetShaderiv_(GLuint shader, GLenum pname, GLint *params) override; + virtual void glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) override; + virtual void glEnable_(GLenum cap) override; + virtual void glDisable_(GLenum cap) override; + virtual GLboolean glIsEnabled_(GLenum cap) override; + virtual void glGetIntegerv_(GLenum pname, GLint *data) override; + virtual const GLubyte* glGetString_(GLenum name) override; + virtual GLenum glCheckFramebufferStatus_(GLenum target) override; + + virtual void glActiveTexture_(GLenum texture) override {} + virtual void glAttachShader_(GLuint program, GLuint shader) override {} + virtual void glBindAttribLocation_(GLuint program, GLuint index, const GLchar *name) override {} + virtual void glBindBuffer_(GLenum target, GLuint buffer) override {} + virtual void glBindFramebuffer_(GLenum target, GLuint framebuffer) override {} + virtual void glBindRenderbuffer_(GLenum target, GLuint renderbuffer) override {} + virtual void glBindTexture_(GLenum target, GLuint texture) override {} + virtual void glBlendColor_(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) override {} + virtual void glBlendEquation_(GLenum mode) override {} + virtual void glBlendEquationSeparate_(GLenum modeRGB, GLenum modeAlpha) override {} + virtual void glBlendFunc_(GLenum sfactor, GLenum dfactor) override {} + virtual void glBlendFuncSeparate_(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) override {} + virtual void glBufferData_(GLenum target, GLsizeiptr size, const void *data, GLenum usage) override {} + virtual void glBufferSubData_(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) override {} + virtual void glClear_(GLbitfield mask) override {} + virtual void glClearColor_(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) override {} + virtual void glClearDepthf_(GLfloat d) override {} + virtual void glClearStencil_(GLint s) override {} + virtual void glColorMask_(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) override {} + virtual void glCompileShader_(GLuint shader) override {} + virtual void glCompressedTexImage2D_(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) override {} + virtual void glCompressedTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) override {} + virtual void glCopyTexImage2D_(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) override {} + virtual void glCopyTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) override {} + virtual void glCullFace_(GLenum mode) override {} + virtual void glDeleteBuffers_(GLsizei n, const GLuint *buffers) override {} + virtual void glDeleteFramebuffers_(GLsizei n, const GLuint *framebuffers) override {} + virtual void glDeleteProgram_(GLuint program) override {} + virtual void glDeleteRenderbuffers_(GLsizei n, const GLuint *renderbuffers) override {} + virtual void glDeleteShader_(GLuint shader) override {} + virtual void glDeleteTextures_(GLsizei n, const GLuint *textures) override {} + virtual void glDepthFunc_(GLenum func) override {} + virtual void glDepthMask_(GLboolean flag) override {} + virtual void glDepthRangef_(GLfloat n, GLfloat f) override {} + virtual void glDetachShader_(GLuint program, GLuint shader) override {} + virtual void glDisableVertexAttribArray_(GLuint index) override {} + virtual void glDrawArrays_(GLenum mode, GLint first, GLsizei count) override {} + virtual void glDrawElements_(GLenum mode, GLsizei count, GLenum type, const void *indices) override {} + virtual void glEnableVertexAttribArray_(GLuint index) override {} + virtual void glFinish_(void) override {} + virtual void glFlush_(void) override {} + virtual void glFramebufferRenderbuffer_(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) override {} + virtual void glFramebufferTexture2D_(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) override {} + virtual void glFrontFace_(GLenum mode) override {} + virtual void glGenerateMipmap_(GLenum target) override {} + virtual GLint glGetAttribLocation_(GLuint program, const GLchar *name) override { return 1; } + virtual GLenum glGetError_(void) override { return GL_NO_ERROR; } + virtual GLint glGetUniformLocation_(GLuint program, const GLchar *name) override { return 2; } + virtual void glHint_(GLenum target, GLenum mode) override {} + virtual void glLineWidth_(GLfloat width) override {} + virtual void glLinkProgram_(GLuint program) override {} + virtual void glPixelStorei_(GLenum pname, GLint param) override {} + virtual void glPolygonOffset_(GLfloat factor, GLfloat units) override {} + virtual void glReadPixels_(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) override {} + virtual void glReleaseShaderCompiler_(void) override {} + virtual void glRenderbufferStorage_(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) override {} + virtual void glSampleCoverage_(GLfloat value, GLboolean invert) override {} + virtual void glScissor_(GLint x, GLint y, GLsizei width, GLsizei height) override {} + virtual void glShaderBinary_(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) override {} + virtual void glShaderSource_(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) override {} + virtual void glStencilFunc_(GLenum func, GLint ref, GLuint mask) override {} + virtual void glStencilFuncSeparate_(GLenum face, GLenum func, GLint ref, GLuint mask) override {} + virtual void glStencilMask_(GLuint mask) override {} + virtual void glStencilMaskSeparate_(GLenum face, GLuint mask) override {} + virtual void glStencilOp_(GLenum fail, GLenum zfail, GLenum zpass) override {} + virtual void glStencilOpSeparate_(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) override {} + virtual void glTexImage2D_(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) override {} + virtual void glTexParameterf_(GLenum target, GLenum pname, GLfloat param) override {} + virtual void glTexParameterfv_(GLenum target, GLenum pname, const GLfloat *params) override {} + virtual void glTexParameteri_(GLenum target, GLenum pname, GLint param) override {} + virtual void glTexParameteriv_(GLenum target, GLenum pname, const GLint *params) override {} + virtual void glTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) override {} + virtual void glUniform1f_(GLint location, GLfloat v0) override {} + virtual void glUniform1fv_(GLint location, GLsizei count, const GLfloat *value) override {} + virtual void glUniform1i_(GLint location, GLint v0) override {} + virtual void glUniform1iv_(GLint location, GLsizei count, const GLint *value) override {} + virtual void glUniform2f_(GLint location, GLfloat v0, GLfloat v1) override {} + virtual void glUniform2fv_(GLint location, GLsizei count, const GLfloat *value) override {} + virtual void glUniform2i_(GLint location, GLint v0, GLint v1) override {} + virtual void glUniform2iv_(GLint location, GLsizei count, const GLint *value) override {} + virtual void glUniform3f_(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) override {} + virtual void glUniform3fv_(GLint location, GLsizei count, const GLfloat *value) override {} + virtual void glUniform3i_(GLint location, GLint v0, GLint v1, GLint v2) override {} + virtual void glUniform3iv_(GLint location, GLsizei count, const GLint *value) override {} + virtual void glUniform4f_(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) override {} + virtual void glUniform4fv_(GLint location, GLsizei count, const GLfloat *value) override {} + virtual void glUniform4i_(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) override {} + virtual void glUniform4iv_(GLint location, GLsizei count, const GLint *value) override {} + virtual void glUniformMatrix2fv_(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override {} + virtual void glUniformMatrix3fv_(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override {} + virtual void glUniformMatrix4fv_(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override {} + virtual void glUseProgram_(GLuint program) override {} + virtual void glValidateProgram_(GLuint program) override {} + virtual void glVertexAttrib1f_(GLuint index, GLfloat x) override {} + virtual void glVertexAttrib1fv_(GLuint index, const GLfloat *v) override {} + virtual void glVertexAttrib2f_(GLuint index, GLfloat x, GLfloat y) override {} + virtual void glVertexAttrib2fv_(GLuint index, const GLfloat *v) override {} + virtual void glVertexAttrib3f_(GLuint index, GLfloat x, GLfloat y, GLfloat z) override {} + virtual void glVertexAttrib3fv_(GLuint index, const GLfloat *v) override {} + virtual void glVertexAttrib4f_(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) override {} + virtual void glVertexAttrib4fv_(GLuint index, const GLfloat *v) override {} + virtual void glVertexAttribPointer_(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) override {} + virtual void glViewport_(GLint x, GLint y, GLsizei width, GLsizei height) override {} + + // gles2 ext + virtual void glInsertEventMarkerEXT_(GLsizei length, const GLchar *marker) override {} + virtual void glPushGroupMarkerEXT_(GLsizei length, const GLchar *marker) override {} + virtual void glPopGroupMarkerEXT_(void) override {} + virtual void glDiscardFramebufferEXT_(GLenum target, GLsizei numAttachments, const GLenum *attachments) override {} + virtual void glEGLImageTargetTexture2DOES_(GLenum target, GLeglImageOES image) override {} + + // GLES3 + virtual void* glMapBufferRange_(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) override { + return 0; + } + + virtual GLboolean glUnmapBuffer_(GLenum target) override { + return GL_FALSE; + } +}; + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/ScopedReplaceDriver.h b/libs/hwui/debug/ScopedReplaceDriver.h new file mode 100644 index 000000000000..342c9d223727 --- /dev/null +++ b/libs/hwui/debug/ScopedReplaceDriver.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "GlesDriver.h" + +namespace android { +namespace uirenderer { +namespace debug { + +template <typename Driver> +class ScopedReplaceDriver { +public: + ScopedReplaceDriver() { + std::unique_ptr<Driver> glDriver = std::make_unique<Driver>(); + mCurrentDriver = glDriver.get(); + mOldDriver = GlesDriver::replace(std::move(glDriver)); + } + + Driver& get() { return *mCurrentDriver; } + + ~ScopedReplaceDriver() { + GlesDriver::replace(std::move(mOldDriver)); + } +private: + std::unique_ptr<GlesDriver> mOldDriver; + Driver* mCurrentDriver; +}; + +} // namespace debug +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/debug/gles_decls.in b/libs/hwui/debug/gles_decls.in new file mode 100644 index 000000000000..16574a7fb074 --- /dev/null +++ b/libs/hwui/debug/gles_decls.in @@ -0,0 +1,544 @@ +GL_ENTRY(void, glActiveTexture, GLenum texture) +GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader) +GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const GLchar *name) +GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer) +GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer) +GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer) +GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture) +GL_ENTRY(void, glBlendColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +GL_ENTRY(void, glBlendEquation, GLenum mode) +GL_ENTRY(void, glBlendEquationSeparate, GLenum modeRGB, GLenum modeAlpha) +GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor) +GL_ENTRY(void, glBlendFuncSeparate, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) +GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const void *data, GLenum usage) +GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void *data) +GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target) +GL_ENTRY(void, glClear, GLbitfield mask) +GL_ENTRY(void, glClearColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +GL_ENTRY(void, glClearDepthf, GLfloat d) +GL_ENTRY(void, glClearStencil, GLint s) +GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +GL_ENTRY(void, glCompileShader, GLuint shader) +GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) +GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) +GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(GLuint, glCreateProgram, void) +GL_ENTRY(GLuint, glCreateShader, GLenum type) +GL_ENTRY(void, glCullFace, GLenum mode) +GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers) +GL_ENTRY(void, glDeleteFramebuffers, GLsizei n, const GLuint *framebuffers) +GL_ENTRY(void, glDeleteProgram, GLuint program) +GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint *renderbuffers) +GL_ENTRY(void, glDeleteShader, GLuint shader) +GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures) +GL_ENTRY(void, glDepthFunc, GLenum func) +GL_ENTRY(void, glDepthMask, GLboolean flag) +GL_ENTRY(void, glDepthRangef, GLfloat n, GLfloat f) +GL_ENTRY(void, glDetachShader, GLuint program, GLuint shader) +GL_ENTRY(void, glDisable, GLenum cap) +GL_ENTRY(void, glDisableVertexAttribArray, GLuint index) +GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count) +GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const void *indices) +GL_ENTRY(void, glEnable, GLenum cap) +GL_ENTRY(void, glEnableVertexAttribArray, GLuint index) +GL_ENTRY(void, glFinish, void) +GL_ENTRY(void, glFlush, void) +GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +GL_ENTRY(void, glFrontFace, GLenum mode) +GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers) +GL_ENTRY(void, glGenerateMipmap, GLenum target) +GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint *framebuffers) +GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint *renderbuffers) +GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures) +GL_ENTRY(void, glGetActiveAttrib, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +GL_ENTRY(void, glGetActiveUniform, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +GL_ENTRY(void, glGetAttachedShaders, GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders) +GL_ENTRY(GLint, glGetAttribLocation, GLuint program, const GLchar *name) +GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *data) +GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(GLenum, glGetError, void) +GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *data) +GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint *params) +GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *data) +GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint *params) +GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) +GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetShaderiv, GLuint shader, GLenum pname, GLint *params) +GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) +GL_ENTRY(void, glGetShaderPrecisionFormat, GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision) +GL_ENTRY(void, glGetShaderSource, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) +GL_ENTRY(const GLubyte *, glGetString, GLenum name) +GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetUniformfv, GLuint program, GLint location, GLfloat *params) +GL_ENTRY(void, glGetUniformiv, GLuint program, GLint location, GLint *params) +GL_ENTRY(GLint, glGetUniformLocation, GLuint program, const GLchar *name) +GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat *params) +GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint *params) +GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, void **pointer) +GL_ENTRY(void, glHint, GLenum target, GLenum mode) +GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer) +GL_ENTRY(GLboolean, glIsEnabled, GLenum cap) +GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer) +GL_ENTRY(GLboolean, glIsProgram, GLuint program) +GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer) +GL_ENTRY(GLboolean, glIsShader, GLuint shader) +GL_ENTRY(GLboolean, glIsTexture, GLuint texture) +GL_ENTRY(void, glLineWidth, GLfloat width) +GL_ENTRY(void, glLinkProgram, GLuint program) +GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param) +GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units) +GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) +GL_ENTRY(void, glReleaseShaderCompiler, void) +GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glSampleCoverage, GLfloat value, GLboolean invert) +GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glShaderBinary, GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) +GL_ENTRY(void, glShaderSource, GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) +GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask) +GL_ENTRY(void, glStencilFuncSeparate, GLenum face, GLenum func, GLint ref, GLuint mask) +GL_ENTRY(void, glStencilMask, GLuint mask) +GL_ENTRY(void, glStencilMaskSeparate, GLenum face, GLuint mask) +GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass) +GL_ENTRY(void, glStencilOpSeparate, GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) +GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) +GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param) +GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params) +GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +GL_ENTRY(void, glUniform1f, GLint location, GLfloat v0) +GL_ENTRY(void, glUniform1fv, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glUniform1i, GLint location, GLint v0) +GL_ENTRY(void, glUniform1iv, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glUniform2f, GLint location, GLfloat v0, GLfloat v1) +GL_ENTRY(void, glUniform2fv, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glUniform2i, GLint location, GLint v0, GLint v1) +GL_ENTRY(void, glUniform2iv, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glUniform3f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +GL_ENTRY(void, glUniform3fv, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glUniform3i, GLint location, GLint v0, GLint v1, GLint v2) +GL_ENTRY(void, glUniform3iv, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glUniform4f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +GL_ENTRY(void, glUniform4fv, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glUniform4i, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +GL_ENTRY(void, glUniform4iv, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glUniformMatrix2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUseProgram, GLuint program) +GL_ENTRY(void, glValidateProgram, GLuint program) +GL_ENTRY(void, glVertexAttrib1f, GLuint index, GLfloat x) +GL_ENTRY(void, glVertexAttrib1fv, GLuint index, const GLfloat *v) +GL_ENTRY(void, glVertexAttrib2f, GLuint index, GLfloat x, GLfloat y) +GL_ENTRY(void, glVertexAttrib2fv, GLuint index, const GLfloat *v) +GL_ENTRY(void, glVertexAttrib3f, GLuint index, GLfloat x, GLfloat y, GLfloat z) +GL_ENTRY(void, glVertexAttrib3fv, GLuint index, const GLfloat *v) +GL_ENTRY(void, glVertexAttrib4f, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +GL_ENTRY(void, glVertexAttrib4fv, GLuint index, const GLfloat *v) +GL_ENTRY(void, glVertexAttribPointer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) +GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glReadBuffer, GLenum src) +GL_ENTRY(void, glDrawRangeElements, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices) +GL_ENTRY(void, glTexImage3D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) +GL_ENTRY(void, glTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels) +GL_ENTRY(void, glCopyTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glCompressedTexImage3D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) +GL_ENTRY(void, glCompressedTexSubImage3D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) +GL_ENTRY(void, glGenQueries, GLsizei n, GLuint *ids) +GL_ENTRY(void, glDeleteQueries, GLsizei n, const GLuint *ids) +GL_ENTRY(GLboolean, glIsQuery, GLuint id) +GL_ENTRY(void, glBeginQuery, GLenum target, GLuint id) +GL_ENTRY(void, glEndQuery, GLenum target) +GL_ENTRY(void, glGetQueryiv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetQueryObjectuiv, GLuint id, GLenum pname, GLuint *params) +GL_ENTRY(GLboolean, glUnmapBuffer, GLenum target) +GL_ENTRY(void, glGetBufferPointerv, GLenum target, GLenum pname, void **params) +GL_ENTRY(void, glDrawBuffers, GLsizei n, const GLenum *bufs) +GL_ENTRY(void, glUniformMatrix2x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix3x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix2x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix4x2fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix3x4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUniformMatrix4x3fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glBlitFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +GL_ENTRY(void, glRenderbufferStorageMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glFramebufferTextureLayer, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) +GL_ENTRY(void *, glMapBufferRange, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +GL_ENTRY(void, glFlushMappedBufferRange, GLenum target, GLintptr offset, GLsizeiptr length) +GL_ENTRY(void, glBindVertexArray, GLuint array) +GL_ENTRY(void, glDeleteVertexArrays, GLsizei n, const GLuint *arrays) +GL_ENTRY(void, glGenVertexArrays, GLsizei n, GLuint *arrays) +GL_ENTRY(GLboolean, glIsVertexArray, GLuint array) +GL_ENTRY(void, glGetIntegeri_v, GLenum target, GLuint index, GLint *data) +GL_ENTRY(void, glBeginTransformFeedback, GLenum primitiveMode) +GL_ENTRY(void, glEndTransformFeedback, void) +GL_ENTRY(void, glBindBufferRange, GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) +GL_ENTRY(void, glBindBufferBase, GLenum target, GLuint index, GLuint buffer) +GL_ENTRY(void, glTransformFeedbackVaryings, GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode) +GL_ENTRY(void, glGetTransformFeedbackVarying, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) +GL_ENTRY(void, glVertexAttribIPointer, GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer) +GL_ENTRY(void, glGetVertexAttribIiv, GLuint index, GLenum pname, GLint *params) +GL_ENTRY(void, glGetVertexAttribIuiv, GLuint index, GLenum pname, GLuint *params) +GL_ENTRY(void, glVertexAttribI4i, GLuint index, GLint x, GLint y, GLint z, GLint w) +GL_ENTRY(void, glVertexAttribI4ui, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) +GL_ENTRY(void, glVertexAttribI4iv, GLuint index, const GLint *v) +GL_ENTRY(void, glVertexAttribI4uiv, GLuint index, const GLuint *v) +GL_ENTRY(void, glGetUniformuiv, GLuint program, GLint location, GLuint *params) +GL_ENTRY(GLint, glGetFragDataLocation, GLuint program, const GLchar *name) +GL_ENTRY(void, glUniform1ui, GLint location, GLuint v0) +GL_ENTRY(void, glUniform2ui, GLint location, GLuint v0, GLuint v1) +GL_ENTRY(void, glUniform3ui, GLint location, GLuint v0, GLuint v1, GLuint v2) +GL_ENTRY(void, glUniform4ui, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +GL_ENTRY(void, glUniform1uiv, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glUniform2uiv, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glUniform3uiv, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glUniform4uiv, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glClearBufferiv, GLenum buffer, GLint drawbuffer, const GLint *value) +GL_ENTRY(void, glClearBufferuiv, GLenum buffer, GLint drawbuffer, const GLuint *value) +GL_ENTRY(void, glClearBufferfv, GLenum buffer, GLint drawbuffer, const GLfloat *value) +GL_ENTRY(void, glClearBufferfi, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) +GL_ENTRY(const GLubyte *, glGetStringi, GLenum name, GLuint index) +GL_ENTRY(void, glCopyBufferSubData, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) +GL_ENTRY(void, glGetUniformIndices, GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices) +GL_ENTRY(void, glGetActiveUniformsiv, GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params) +GL_ENTRY(GLuint, glGetUniformBlockIndex, GLuint program, const GLchar *uniformBlockName) +GL_ENTRY(void, glGetActiveUniformBlockiv, GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params) +GL_ENTRY(void, glGetActiveUniformBlockName, GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) +GL_ENTRY(void, glUniformBlockBinding, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) +GL_ENTRY(void, glDrawArraysInstanced, GLenum mode, GLint first, GLsizei count, GLsizei instancecount) +GL_ENTRY(void, glDrawElementsInstanced, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount) +GL_ENTRY(GLsync, glFenceSync, GLenum condition, GLbitfield flags) +GL_ENTRY(GLboolean, glIsSync, GLsync sync) +GL_ENTRY(void, glDeleteSync, GLsync sync) +GL_ENTRY(GLenum, glClientWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) +GL_ENTRY(void, glWaitSync, GLsync sync, GLbitfield flags, GLuint64 timeout) +GL_ENTRY(void, glGetInteger64v, GLenum pname, GLint64 *data) +GL_ENTRY(void, glGetSynciv, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) +GL_ENTRY(void, glGetInteger64i_v, GLenum target, GLuint index, GLint64 *data) +GL_ENTRY(void, glGetBufferParameteri64v, GLenum target, GLenum pname, GLint64 *params) +GL_ENTRY(void, glGenSamplers, GLsizei count, GLuint *samplers) +GL_ENTRY(void, glDeleteSamplers, GLsizei count, const GLuint *samplers) +GL_ENTRY(GLboolean, glIsSampler, GLuint sampler) +GL_ENTRY(void, glBindSampler, GLuint unit, GLuint sampler) +GL_ENTRY(void, glSamplerParameteri, GLuint sampler, GLenum pname, GLint param) +GL_ENTRY(void, glSamplerParameteriv, GLuint sampler, GLenum pname, const GLint *param) +GL_ENTRY(void, glSamplerParameterf, GLuint sampler, GLenum pname, GLfloat param) +GL_ENTRY(void, glSamplerParameterfv, GLuint sampler, GLenum pname, const GLfloat *param) +GL_ENTRY(void, glGetSamplerParameteriv, GLuint sampler, GLenum pname, GLint *params) +GL_ENTRY(void, glGetSamplerParameterfv, GLuint sampler, GLenum pname, GLfloat *params) +GL_ENTRY(void, glVertexAttribDivisor, GLuint index, GLuint divisor) +GL_ENTRY(void, glBindTransformFeedback, GLenum target, GLuint id) +GL_ENTRY(void, glDeleteTransformFeedbacks, GLsizei n, const GLuint *ids) +GL_ENTRY(void, glGenTransformFeedbacks, GLsizei n, GLuint *ids) +GL_ENTRY(GLboolean, glIsTransformFeedback, GLuint id) +GL_ENTRY(void, glPauseTransformFeedback, void) +GL_ENTRY(void, glResumeTransformFeedback, void) +GL_ENTRY(void, glGetProgramBinary, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) +GL_ENTRY(void, glProgramBinary, GLuint program, GLenum binaryFormat, const void *binary, GLsizei length) +GL_ENTRY(void, glProgramParameteri, GLuint program, GLenum pname, GLint value) +GL_ENTRY(void, glInvalidateFramebuffer, GLenum target, GLsizei numAttachments, const GLenum *attachments) +GL_ENTRY(void, glInvalidateSubFramebuffer, GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glTexStorage2D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glTexStorage3D, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +GL_ENTRY(void, glGetInternalformativ, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) +GL_ENTRY(void, glDispatchCompute, GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) +GL_ENTRY(void, glDispatchComputeIndirect, GLintptr indirect) +GL_ENTRY(void, glDrawArraysIndirect, GLenum mode, const void *indirect) +GL_ENTRY(void, glDrawElementsIndirect, GLenum mode, GLenum type, const void *indirect) +GL_ENTRY(void, glFramebufferParameteri, GLenum target, GLenum pname, GLint param) +GL_ENTRY(void, glGetFramebufferParameteriv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint *params) +GL_ENTRY(GLuint, glGetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar *name) +GL_ENTRY(void, glGetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) +GL_ENTRY(void, glGetProgramResourceiv, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params) +GL_ENTRY(GLint, glGetProgramResourceLocation, GLuint program, GLenum programInterface, const GLchar *name) +GL_ENTRY(void, glUseProgramStages, GLuint pipeline, GLbitfield stages, GLuint program) +GL_ENTRY(void, glActiveShaderProgram, GLuint pipeline, GLuint program) +GL_ENTRY(GLuint, glCreateShaderProgramv, GLenum type, GLsizei count, const GLchar *const*strings) +GL_ENTRY(void, glBindProgramPipeline, GLuint pipeline) +GL_ENTRY(void, glDeleteProgramPipelines, GLsizei n, const GLuint *pipelines) +GL_ENTRY(void, glGenProgramPipelines, GLsizei n, GLuint *pipelines) +GL_ENTRY(GLboolean, glIsProgramPipeline, GLuint pipeline) +GL_ENTRY(void, glGetProgramPipelineiv, GLuint pipeline, GLenum pname, GLint *params) +GL_ENTRY(void, glProgramUniform1i, GLuint program, GLint location, GLint v0) +GL_ENTRY(void, glProgramUniform2i, GLuint program, GLint location, GLint v0, GLint v1) +GL_ENTRY(void, glProgramUniform3i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2) +GL_ENTRY(void, glProgramUniform4i, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +GL_ENTRY(void, glProgramUniform1ui, GLuint program, GLint location, GLuint v0) +GL_ENTRY(void, glProgramUniform2ui, GLuint program, GLint location, GLuint v0, GLuint v1) +GL_ENTRY(void, glProgramUniform3ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) +GL_ENTRY(void, glProgramUniform4ui, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +GL_ENTRY(void, glProgramUniform1f, GLuint program, GLint location, GLfloat v0) +GL_ENTRY(void, glProgramUniform2f, GLuint program, GLint location, GLfloat v0, GLfloat v1) +GL_ENTRY(void, glProgramUniform3f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +GL_ENTRY(void, glProgramUniform4f, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +GL_ENTRY(void, glProgramUniform1iv, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform2iv, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform3iv, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform4iv, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform1uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform2uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform3uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform4uiv, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform1fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform2fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform3fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform4fv, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix2x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix3x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix2x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix4x2fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix3x4fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix4x3fv, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glValidateProgramPipeline, GLuint pipeline) +GL_ENTRY(void, glGetProgramPipelineInfoLog, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) +GL_ENTRY(void, glBindImageTexture, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) +GL_ENTRY(void, glGetBooleani_v, GLenum target, GLuint index, GLboolean *data) +GL_ENTRY(void, glMemoryBarrier, GLbitfield barriers) +GL_ENTRY(void, glMemoryBarrierByRegion, GLbitfield barriers) +GL_ENTRY(void, glTexStorage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) +GL_ENTRY(void, glGetMultisamplefv, GLenum pname, GLuint index, GLfloat *val) +GL_ENTRY(void, glSampleMaski, GLuint maskNumber, GLbitfield mask) +GL_ENTRY(void, glGetTexLevelParameteriv, GLenum target, GLint level, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexLevelParameterfv, GLenum target, GLint level, GLenum pname, GLfloat *params) +GL_ENTRY(void, glBindVertexBuffer, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) +GL_ENTRY(void, glVertexAttribFormat, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) +GL_ENTRY(void, glVertexAttribIFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) +GL_ENTRY(void, glVertexAttribBinding, GLuint attribindex, GLuint bindingindex) +GL_ENTRY(void, glVertexBindingDivisor, GLuint bindingindex, GLuint divisor) +GL_ENTRY(void, glBlendBarrier, void) +GL_ENTRY(void, glCopyImageSubData, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) +GL_ENTRY(void, glDebugMessageControl, GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled) +GL_ENTRY(void, glDebugMessageInsert, GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf) +GL_ENTRY(void, glDebugMessageCallback, GLDEBUGPROC callback, const void *userParam) +GL_ENTRY(GLuint, glGetDebugMessageLog, GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog) +GL_ENTRY(void, glPushDebugGroup, GLenum source, GLuint id, GLsizei length, const GLchar *message) +GL_ENTRY(void, glPopDebugGroup, void) +GL_ENTRY(void, glObjectLabel, GLenum identifier, GLuint name, GLsizei length, const GLchar *label) +GL_ENTRY(void, glGetObjectLabel, GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label) +GL_ENTRY(void, glObjectPtrLabel, const void *ptr, GLsizei length, const GLchar *label) +GL_ENTRY(void, glGetObjectPtrLabel, const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) +GL_ENTRY(void, glGetPointerv, GLenum pname, void **params) +GL_ENTRY(void, glEnablei, GLenum target, GLuint index) +GL_ENTRY(void, glDisablei, GLenum target, GLuint index) +GL_ENTRY(void, glBlendEquationi, GLuint buf, GLenum mode) +GL_ENTRY(void, glBlendEquationSeparatei, GLuint buf, GLenum modeRGB, GLenum modeAlpha) +GL_ENTRY(void, glBlendFunci, GLuint buf, GLenum src, GLenum dst) +GL_ENTRY(void, glBlendFuncSeparatei, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +GL_ENTRY(void, glColorMaski, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) +GL_ENTRY(GLboolean, glIsEnabledi, GLenum target, GLuint index) +GL_ENTRY(void, glDrawElementsBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) +GL_ENTRY(void, glDrawRangeElementsBaseVertex, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) +GL_ENTRY(void, glDrawElementsInstancedBaseVertex, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) +GL_ENTRY(void, glFramebufferTexture, GLenum target, GLenum attachment, GLuint texture, GLint level) +GL_ENTRY(void, glPrimitiveBoundingBox, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) +GL_ENTRY(GLenum, glGetGraphicsResetStatus, void) +GL_ENTRY(void, glReadnPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) +GL_ENTRY(void, glGetnUniformfv, GLuint program, GLint location, GLsizei bufSize, GLfloat *params) +GL_ENTRY(void, glGetnUniformiv, GLuint program, GLint location, GLsizei bufSize, GLint *params) +GL_ENTRY(void, glGetnUniformuiv, GLuint program, GLint location, GLsizei bufSize, GLuint *params) +GL_ENTRY(void, glMinSampleShading, GLfloat value) +GL_ENTRY(void, glPatchParameteri, GLenum pname, GLint value) +GL_ENTRY(void, glTexParameterIiv, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexParameterIuiv, GLenum target, GLenum pname, const GLuint *params) +GL_ENTRY(void, glGetTexParameterIiv, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexParameterIuiv, GLenum target, GLenum pname, GLuint *params) +GL_ENTRY(void, glSamplerParameterIiv, GLuint sampler, GLenum pname, const GLint *param) +GL_ENTRY(void, glSamplerParameterIuiv, GLuint sampler, GLenum pname, const GLuint *param) +GL_ENTRY(void, glGetSamplerParameterIiv, GLuint sampler, GLenum pname, GLint *params) +GL_ENTRY(void, glGetSamplerParameterIuiv, GLuint sampler, GLenum pname, GLuint *params) +GL_ENTRY(void, glTexBuffer, GLenum target, GLenum internalformat, GLuint buffer) +GL_ENTRY(void, glTexBufferRange, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) +GL_ENTRY(void, glTexStorage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) +GL_ENTRY(void, glBlendBarrierKHR, void) +GL_ENTRY(void, glDebugMessageControlKHR, GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled) +GL_ENTRY(void, glDebugMessageInsertKHR, GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf) +GL_ENTRY(void, glDebugMessageCallbackKHR, GLDEBUGPROCKHR callback, const void *userParam) +GL_ENTRY(GLuint, glGetDebugMessageLogKHR, GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog) +GL_ENTRY(void, glPushDebugGroupKHR, GLenum source, GLuint id, GLsizei length, const GLchar *message) +GL_ENTRY(void, glPopDebugGroupKHR, void) +GL_ENTRY(void, glObjectLabelKHR, GLenum identifier, GLuint name, GLsizei length, const GLchar *label) +GL_ENTRY(void, glGetObjectLabelKHR, GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label) +GL_ENTRY(void, glObjectPtrLabelKHR, const void *ptr, GLsizei length, const GLchar *label) +GL_ENTRY(void, glGetObjectPtrLabelKHR, const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) +GL_ENTRY(void, glGetPointervKHR, GLenum pname, void **params) +GL_ENTRY(GLenum, glGetGraphicsResetStatusKHR, void) +GL_ENTRY(void, glReadnPixelsKHR, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) +GL_ENTRY(void, glGetnUniformfvKHR, GLuint program, GLint location, GLsizei bufSize, GLfloat *params) +GL_ENTRY(void, glGetnUniformivKHR, GLuint program, GLint location, GLsizei bufSize, GLint *params) +GL_ENTRY(void, glGetnUniformuivKHR, GLuint program, GLint location, GLsizei bufSize, GLuint *params) +GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image) +GL_ENTRY(void, glCopyImageSubDataOES, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) +GL_ENTRY(void, glEnableiOES, GLenum target, GLuint index) +GL_ENTRY(void, glDisableiOES, GLenum target, GLuint index) +GL_ENTRY(void, glBlendEquationiOES, GLuint buf, GLenum mode) +GL_ENTRY(void, glBlendEquationSeparateiOES, GLuint buf, GLenum modeRGB, GLenum modeAlpha) +GL_ENTRY(void, glBlendFunciOES, GLuint buf, GLenum src, GLenum dst) +GL_ENTRY(void, glBlendFuncSeparateiOES, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +GL_ENTRY(void, glColorMaskiOES, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) +GL_ENTRY(GLboolean, glIsEnablediOES, GLenum target, GLuint index) +GL_ENTRY(void, glDrawElementsBaseVertexOES, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) +GL_ENTRY(void, glDrawRangeElementsBaseVertexOES, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) +GL_ENTRY(void, glDrawElementsInstancedBaseVertexOES, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) +GL_ENTRY(void, glMultiDrawElementsBaseVertexOES, GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) +GL_ENTRY(void, glFramebufferTextureOES, GLenum target, GLenum attachment, GLuint texture, GLint level) +GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) +GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const void *binary, GLint length) +GL_ENTRY(void *, glMapBufferOES, GLenum target, GLenum access) +GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target) +GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void **params) +GL_ENTRY(void, glPrimitiveBoundingBoxOES, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) +GL_ENTRY(void, glMinSampleShadingOES, GLfloat value) +GL_ENTRY(void, glPatchParameteriOES, GLenum pname, GLint value) +GL_ENTRY(void, glTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) +GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels) +GL_ENTRY(void, glCopyTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +GL_ENTRY(void, glCompressedTexImage3DOES, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) +GL_ENTRY(void, glCompressedTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) +GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) +GL_ENTRY(void, glTexParameterIivOES, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexParameterIuivOES, GLenum target, GLenum pname, const GLuint *params) +GL_ENTRY(void, glGetTexParameterIivOES, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexParameterIuivOES, GLenum target, GLenum pname, GLuint *params) +GL_ENTRY(void, glSamplerParameterIivOES, GLuint sampler, GLenum pname, const GLint *param) +GL_ENTRY(void, glSamplerParameterIuivOES, GLuint sampler, GLenum pname, const GLuint *param) +GL_ENTRY(void, glGetSamplerParameterIivOES, GLuint sampler, GLenum pname, GLint *params) +GL_ENTRY(void, glGetSamplerParameterIuivOES, GLuint sampler, GLenum pname, GLuint *params) +GL_ENTRY(void, glTexBufferOES, GLenum target, GLenum internalformat, GLuint buffer) +GL_ENTRY(void, glTexBufferRangeOES, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) +GL_ENTRY(void, glTexStorage3DMultisampleOES, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) +GL_ENTRY(void, glTextureViewOES, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) +GL_ENTRY(void, glBindVertexArrayOES, GLuint array) +GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays) +GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays) +GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array) +GL_ENTRY(void, glDrawArraysInstancedBaseInstanceEXT, GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance) +GL_ENTRY(void, glDrawElementsInstancedBaseInstanceEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance) +GL_ENTRY(void, glDrawElementsInstancedBaseVertexBaseInstanceEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance) +GL_ENTRY(void, glBindFragDataLocationIndexedEXT, GLuint program, GLuint colorNumber, GLuint index, const GLchar *name) +GL_ENTRY(void, glBindFragDataLocationEXT, GLuint program, GLuint color, const GLchar *name) +GL_ENTRY(GLint, glGetProgramResourceLocationIndexEXT, GLuint program, GLenum programInterface, const GLchar *name) +GL_ENTRY(GLint, glGetFragDataIndexEXT, GLuint program, const GLchar *name) +GL_ENTRY(void, glBufferStorageEXT, GLenum target, GLsizeiptr size, const void *data, GLbitfield flags) +GL_ENTRY(void, glCopyImageSubDataEXT, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) +GL_ENTRY(void, glLabelObjectEXT, GLenum type, GLuint object, GLsizei length, const GLchar *label) +GL_ENTRY(void, glGetObjectLabelEXT, GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label) +GL_ENTRY(void, glInsertEventMarkerEXT, GLsizei length, const GLchar *marker) +GL_ENTRY(void, glPushGroupMarkerEXT, GLsizei length, const GLchar *marker) +GL_ENTRY(void, glPopGroupMarkerEXT, void) +GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments) +GL_ENTRY(void, glGenQueriesEXT, GLsizei n, GLuint *ids) +GL_ENTRY(void, glDeleteQueriesEXT, GLsizei n, const GLuint *ids) +GL_ENTRY(GLboolean, glIsQueryEXT, GLuint id) +GL_ENTRY(void, glBeginQueryEXT, GLenum target, GLuint id) +GL_ENTRY(void, glEndQueryEXT, GLenum target) +GL_ENTRY(void, glQueryCounterEXT, GLuint id, GLenum target) +GL_ENTRY(void, glGetQueryivEXT, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetQueryObjectivEXT, GLuint id, GLenum pname, GLint *params) +GL_ENTRY(void, glGetQueryObjectuivEXT, GLuint id, GLenum pname, GLuint *params) +GL_ENTRY(void, glGetQueryObjecti64vEXT, GLuint id, GLenum pname, GLint64 *params) +GL_ENTRY(void, glGetQueryObjectui64vEXT, GLuint id, GLenum pname, GLuint64 *params) +GL_ENTRY(void, glDrawBuffersEXT, GLsizei n, const GLenum *bufs) +GL_ENTRY(void, glEnableiEXT, GLenum target, GLuint index) +GL_ENTRY(void, glDisableiEXT, GLenum target, GLuint index) +GL_ENTRY(void, glBlendEquationiEXT, GLuint buf, GLenum mode) +GL_ENTRY(void, glBlendEquationSeparateiEXT, GLuint buf, GLenum modeRGB, GLenum modeAlpha) +GL_ENTRY(void, glBlendFunciEXT, GLuint buf, GLenum src, GLenum dst) +GL_ENTRY(void, glBlendFuncSeparateiEXT, GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +GL_ENTRY(void, glColorMaskiEXT, GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) +GL_ENTRY(GLboolean, glIsEnablediEXT, GLenum target, GLuint index) +GL_ENTRY(void, glDrawElementsBaseVertexEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) +GL_ENTRY(void, glDrawRangeElementsBaseVertexEXT, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) +GL_ENTRY(void, glDrawElementsInstancedBaseVertexEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) +GL_ENTRY(void, glMultiDrawElementsBaseVertexEXT, GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) +GL_ENTRY(void, glDrawArraysInstancedEXT, GLenum mode, GLint start, GLsizei count, GLsizei primcount) +GL_ENTRY(void, glDrawElementsInstancedEXT, GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) +GL_ENTRY(void, glFramebufferTextureEXT, GLenum target, GLenum attachment, GLuint texture, GLint level) +GL_ENTRY(void, glVertexAttribDivisorEXT, GLuint index, GLuint divisor) +GL_ENTRY(void *, glMapBufferRangeEXT, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +GL_ENTRY(void, glFlushMappedBufferRangeEXT, GLenum target, GLintptr offset, GLsizeiptr length) +GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) +GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount) +GL_ENTRY(void, glMultiDrawArraysIndirectEXT, GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride) +GL_ENTRY(void, glMultiDrawElementsIndirectEXT, GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride) +GL_ENTRY(void, glRenderbufferStorageMultisampleEXT, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glFramebufferTexture2DMultisampleEXT, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) +GL_ENTRY(void, glReadBufferIndexedEXT, GLenum src, GLint index) +GL_ENTRY(void, glDrawBuffersIndexedEXT, GLint n, const GLenum *location, const GLint *indices) +GL_ENTRY(void, glGetIntegeri_vEXT, GLenum target, GLuint index, GLint *data) +GL_ENTRY(void, glPrimitiveBoundingBoxEXT, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) +GL_ENTRY(void, glRasterSamplesEXT, GLuint samples, GLboolean fixedsamplelocations) +GL_ENTRY(GLenum, glGetGraphicsResetStatusEXT, void) +GL_ENTRY(void, glReadnPixelsEXT, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) +GL_ENTRY(void, glGetnUniformfvEXT, GLuint program, GLint location, GLsizei bufSize, GLfloat *params) +GL_ENTRY(void, glGetnUniformivEXT, GLuint program, GLint location, GLsizei bufSize, GLint *params) +GL_ENTRY(void, glActiveShaderProgramEXT, GLuint pipeline, GLuint program) +GL_ENTRY(void, glBindProgramPipelineEXT, GLuint pipeline) +GL_ENTRY(GLuint, glCreateShaderProgramvEXT, GLenum type, GLsizei count, const GLchar **strings) +GL_ENTRY(void, glDeleteProgramPipelinesEXT, GLsizei n, const GLuint *pipelines) +GL_ENTRY(void, glGenProgramPipelinesEXT, GLsizei n, GLuint *pipelines) +GL_ENTRY(void, glGetProgramPipelineInfoLogEXT, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) +GL_ENTRY(void, glGetProgramPipelineivEXT, GLuint pipeline, GLenum pname, GLint *params) +GL_ENTRY(GLboolean, glIsProgramPipelineEXT, GLuint pipeline) +GL_ENTRY(void, glProgramParameteriEXT, GLuint program, GLenum pname, GLint value) +GL_ENTRY(void, glProgramUniform1fEXT, GLuint program, GLint location, GLfloat v0) +GL_ENTRY(void, glProgramUniform1fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform1iEXT, GLuint program, GLint location, GLint v0) +GL_ENTRY(void, glProgramUniform1ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform2fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1) +GL_ENTRY(void, glProgramUniform2fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform2iEXT, GLuint program, GLint location, GLint v0, GLint v1) +GL_ENTRY(void, glProgramUniform2ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform3fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) +GL_ENTRY(void, glProgramUniform3fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform3iEXT, GLuint program, GLint location, GLint v0, GLint v1, GLint v2) +GL_ENTRY(void, glProgramUniform3ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniform4fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) +GL_ENTRY(void, glProgramUniform4fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) +GL_ENTRY(void, glProgramUniform4iEXT, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) +GL_ENTRY(void, glProgramUniform4ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value) +GL_ENTRY(void, glProgramUniformMatrix2fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix3fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glUseProgramStagesEXT, GLuint pipeline, GLbitfield stages, GLuint program) +GL_ENTRY(void, glValidateProgramPipelineEXT, GLuint pipeline) +GL_ENTRY(void, glProgramUniform1uiEXT, GLuint program, GLint location, GLuint v0) +GL_ENTRY(void, glProgramUniform2uiEXT, GLuint program, GLint location, GLuint v0, GLuint v1) +GL_ENTRY(void, glProgramUniform3uiEXT, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) +GL_ENTRY(void, glProgramUniform4uiEXT, GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +GL_ENTRY(void, glProgramUniform1uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform2uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform3uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniform4uivEXT, GLuint program, GLint location, GLsizei count, const GLuint *value) +GL_ENTRY(void, glProgramUniformMatrix2x3fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix3x2fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix2x4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix4x2fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix3x4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glProgramUniformMatrix4x3fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +GL_ENTRY(void, glTexPageCommitmentEXT, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit) +GL_ENTRY(void, glPatchParameteriEXT, GLenum pname, GLint value) +GL_ENTRY(void, glTexParameterIivEXT, GLenum target, GLenum pname, const GLint *params) +GL_ENTRY(void, glTexParameterIuivEXT, GLenum target, GLenum pname, const GLuint *params) +GL_ENTRY(void, glGetTexParameterIivEXT, GLenum target, GLenum pname, GLint *params) +GL_ENTRY(void, glGetTexParameterIuivEXT, GLenum target, GLenum pname, GLuint *params) +GL_ENTRY(void, glSamplerParameterIivEXT, GLuint sampler, GLenum pname, const GLint *param) +GL_ENTRY(void, glSamplerParameterIuivEXT, GLuint sampler, GLenum pname, const GLuint *param) +GL_ENTRY(void, glGetSamplerParameterIivEXT, GLuint sampler, GLenum pname, GLint *params) +GL_ENTRY(void, glGetSamplerParameterIuivEXT, GLuint sampler, GLenum pname, GLuint *params) +GL_ENTRY(void, glTexBufferEXT, GLenum target, GLenum internalformat, GLuint buffer) +GL_ENTRY(void, glTexBufferRangeEXT, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) +GL_ENTRY(void, glTexStorage1DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) +GL_ENTRY(void, glTexStorage2DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glTexStorage3DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +GL_ENTRY(void, glTextureStorage1DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) +GL_ENTRY(void, glTextureStorage2DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +GL_ENTRY(void, glTextureStorage3DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +GL_ENTRY(void, glTextureViewEXT, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers)
\ No newline at end of file diff --git a/libs/hwui/debug/gles_stubs.in b/libs/hwui/debug/gles_stubs.in new file mode 100644 index 000000000000..4064a391a71d --- /dev/null +++ b/libs/hwui/debug/gles_stubs.in @@ -0,0 +1,1632 @@ +void API_ENTRY(glActiveTexture)(GLenum texture) { + CALL_GL_API(glActiveTexture, texture); +} +void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) { + CALL_GL_API(glAttachShader, program, shader); +} +void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const GLchar *name) { + CALL_GL_API(glBindAttribLocation, program, index, name); +} +void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) { + CALL_GL_API(glBindBuffer, target, buffer); +} +void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) { + CALL_GL_API(glBindFramebuffer, target, framebuffer); +} +void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) { + CALL_GL_API(glBindRenderbuffer, target, renderbuffer); +} +void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) { + CALL_GL_API(glBindTexture, target, texture); +} +void API_ENTRY(glBlendColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { + CALL_GL_API(glBlendColor, red, green, blue, alpha); +} +void API_ENTRY(glBlendEquation)(GLenum mode) { + CALL_GL_API(glBlendEquation, mode); +} +void API_ENTRY(glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) { + CALL_GL_API(glBlendEquationSeparate, modeRGB, modeAlpha); +} +void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) { + CALL_GL_API(glBlendFunc, sfactor, dfactor); +} +void API_ENTRY(glBlendFuncSeparate)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) { + CALL_GL_API(glBlendFuncSeparate, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); +} +void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const void *data, GLenum usage) { + CALL_GL_API(glBufferData, target, size, data, usage); +} +void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) { + CALL_GL_API(glBufferSubData, target, offset, size, data); +} +GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) { + CALL_GL_API_RETURN(glCheckFramebufferStatus, target); +} +void API_ENTRY(glClear)(GLbitfield mask) { + CALL_GL_API(glClear, mask); +} +void API_ENTRY(glClearColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { + CALL_GL_API(glClearColor, red, green, blue, alpha); +} +void API_ENTRY(glClearDepthf)(GLfloat d) { + CALL_GL_API(glClearDepthf, d); +} +void API_ENTRY(glClearStencil)(GLint s) { + CALL_GL_API(glClearStencil, s); +} +void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { + CALL_GL_API(glColorMask, red, green, blue, alpha); +} +void API_ENTRY(glCompileShader)(GLuint shader) { + CALL_GL_API(glCompileShader, shader); +} +void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) { + CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data); +} +void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) { + CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data); +} +void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { + CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border); +} +void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height); +} +GLuint API_ENTRY(glCreateProgram)(void) { + CALL_GL_API_RETURN(glCreateProgram); +} +GLuint API_ENTRY(glCreateShader)(GLenum type) { + CALL_GL_API_RETURN(glCreateShader, type); +} +void API_ENTRY(glCullFace)(GLenum mode) { + CALL_GL_API(glCullFace, mode); +} +void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint *buffers) { + CALL_GL_API(glDeleteBuffers, n, buffers); +} +void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint *framebuffers) { + CALL_GL_API(glDeleteFramebuffers, n, framebuffers); +} +void API_ENTRY(glDeleteProgram)(GLuint program) { + CALL_GL_API(glDeleteProgram, program); +} +void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint *renderbuffers) { + CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers); +} +void API_ENTRY(glDeleteShader)(GLuint shader) { + CALL_GL_API(glDeleteShader, shader); +} +void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint *textures) { + CALL_GL_API(glDeleteTextures, n, textures); +} +void API_ENTRY(glDepthFunc)(GLenum func) { + CALL_GL_API(glDepthFunc, func); +} +void API_ENTRY(glDepthMask)(GLboolean flag) { + CALL_GL_API(glDepthMask, flag); +} +void API_ENTRY(glDepthRangef)(GLfloat n, GLfloat f) { + CALL_GL_API(glDepthRangef, n, f); +} +void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) { + CALL_GL_API(glDetachShader, program, shader); +} +void API_ENTRY(glDisable)(GLenum cap) { + CALL_GL_API(glDisable, cap); +} +void API_ENTRY(glDisableVertexAttribArray)(GLuint index) { + CALL_GL_API(glDisableVertexAttribArray, index); +} +void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) { + CALL_GL_API(glDrawArrays, mode, first, count); +} +void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void *indices) { + CALL_GL_API(glDrawElements, mode, count, type, indices); +} +void API_ENTRY(glEnable)(GLenum cap) { + CALL_GL_API(glEnable, cap); +} +void API_ENTRY(glEnableVertexAttribArray)(GLuint index) { + CALL_GL_API(glEnableVertexAttribArray, index); +} +void API_ENTRY(glFinish)(void) { + CALL_GL_API(glFinish); +} +void API_ENTRY(glFlush)(void) { + CALL_GL_API(glFlush); +} +void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { + CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer); +} +void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { + CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level); +} +void API_ENTRY(glFrontFace)(GLenum mode) { + CALL_GL_API(glFrontFace, mode); +} +void API_ENTRY(glGenBuffers)(GLsizei n, GLuint *buffers) { + CALL_GL_API(glGenBuffers, n, buffers); +} +void API_ENTRY(glGenerateMipmap)(GLenum target) { + CALL_GL_API(glGenerateMipmap, target); +} +void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint *framebuffers) { + CALL_GL_API(glGenFramebuffers, n, framebuffers); +} +void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint *renderbuffers) { + CALL_GL_API(glGenRenderbuffers, n, renderbuffers); +} +void API_ENTRY(glGenTextures)(GLsizei n, GLuint *textures) { + CALL_GL_API(glGenTextures, n, textures); +} +void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) { + CALL_GL_API(glGetActiveAttrib, program, index, bufSize, length, size, type, name); +} +void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) { + CALL_GL_API(glGetActiveUniform, program, index, bufSize, length, size, type, name); +} +void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders) { + CALL_GL_API(glGetAttachedShaders, program, maxCount, count, shaders); +} +GLint API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar *name) { + CALL_GL_API_RETURN(glGetAttribLocation, program, name); +} +void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *data) { + CALL_GL_API(glGetBooleanv, pname, data); +} +void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetBufferParameteriv, target, pname, params); +} +GLenum API_ENTRY(glGetError)(void) { + CALL_GL_API_RETURN(glGetError); +} +void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *data) { + CALL_GL_API(glGetFloatv, pname, data); +} +void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint *params) { + CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params); +} +void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *data) { + CALL_GL_API(glGetIntegerv, pname, data); +} +void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint *params) { + CALL_GL_API(glGetProgramiv, program, pname, params); +} +void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { + CALL_GL_API(glGetProgramInfoLog, program, bufSize, length, infoLog); +} +void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params); +} +void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint *params) { + CALL_GL_API(glGetShaderiv, shader, pname, params); +} +void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { + CALL_GL_API(glGetShaderInfoLog, shader, bufSize, length, infoLog); +} +void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision) { + CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision); +} +void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) { + CALL_GL_API(glGetShaderSource, shader, bufSize, length, source); +} +const GLubyte * API_ENTRY(glGetString)(GLenum name) { + CALL_GL_API_RETURN(glGetString, name); +} +void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat *params) { + CALL_GL_API(glGetTexParameterfv, target, pname, params); +} +void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetTexParameteriv, target, pname, params); +} +void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat *params) { + CALL_GL_API(glGetUniformfv, program, location, params); +} +void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint *params) { + CALL_GL_API(glGetUniformiv, program, location, params); +} +GLint API_ENTRY(glGetUniformLocation)(GLuint program, const GLchar *name) { + CALL_GL_API_RETURN(glGetUniformLocation, program, name); +} +void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat *params) { + CALL_GL_API(glGetVertexAttribfv, index, pname, params); +} +void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint *params) { + CALL_GL_API(glGetVertexAttribiv, index, pname, params); +} +void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, void **pointer) { + CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer); +} +void API_ENTRY(glHint)(GLenum target, GLenum mode) { + CALL_GL_API(glHint, target, mode); +} +GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) { + CALL_GL_API_RETURN(glIsBuffer, buffer); +} +GLboolean API_ENTRY(glIsEnabled)(GLenum cap) { + CALL_GL_API_RETURN(glIsEnabled, cap); +} +GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) { + CALL_GL_API_RETURN(glIsFramebuffer, framebuffer); +} +GLboolean API_ENTRY(glIsProgram)(GLuint program) { + CALL_GL_API_RETURN(glIsProgram, program); +} +GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) { + CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer); +} +GLboolean API_ENTRY(glIsShader)(GLuint shader) { + CALL_GL_API_RETURN(glIsShader, shader); +} +GLboolean API_ENTRY(glIsTexture)(GLuint texture) { + CALL_GL_API_RETURN(glIsTexture, texture); +} +void API_ENTRY(glLineWidth)(GLfloat width) { + CALL_GL_API(glLineWidth, width); +} +void API_ENTRY(glLinkProgram)(GLuint program) { + CALL_GL_API(glLinkProgram, program); +} +void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) { + CALL_GL_API(glPixelStorei, pname, param); +} +void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) { + CALL_GL_API(glPolygonOffset, factor, units); +} +void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) { + CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels); +} +void API_ENTRY(glReleaseShaderCompiler)(void) { + CALL_GL_API(glReleaseShaderCompiler); +} +void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { + CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height); +} +void API_ENTRY(glSampleCoverage)(GLfloat value, GLboolean invert) { + CALL_GL_API(glSampleCoverage, value, invert); +} +void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glScissor, x, y, width, height); +} +void API_ENTRY(glShaderBinary)(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) { + CALL_GL_API(glShaderBinary, count, shaders, binaryformat, binary, length); +} +void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) { + CALL_GL_API(glShaderSource, shader, count, string, length); +} +void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) { + CALL_GL_API(glStencilFunc, func, ref, mask); +} +void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) { + CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask); +} +void API_ENTRY(glStencilMask)(GLuint mask) { + CALL_GL_API(glStencilMask, mask); +} +void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) { + CALL_GL_API(glStencilMaskSeparate, face, mask); +} +void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) { + CALL_GL_API(glStencilOp, fail, zfail, zpass); +} +void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) { + CALL_GL_API(glStencilOpSeparate, face, sfail, dpfail, dppass); +} +void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) { + CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels); +} +void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) { + CALL_GL_API(glTexParameterf, target, pname, param); +} +void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat *params) { + CALL_GL_API(glTexParameterfv, target, pname, params); +} +void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) { + CALL_GL_API(glTexParameteri, target, pname, param); +} +void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint *params) { + CALL_GL_API(glTexParameteriv, target, pname, params); +} +void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) { + CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels); +} +void API_ENTRY(glUniform1f)(GLint location, GLfloat v0) { + CALL_GL_API(glUniform1f, location, v0); +} +void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glUniform1fv, location, count, value); +} +void API_ENTRY(glUniform1i)(GLint location, GLint v0) { + CALL_GL_API(glUniform1i, location, v0); +} +void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glUniform1iv, location, count, value); +} +void API_ENTRY(glUniform2f)(GLint location, GLfloat v0, GLfloat v1) { + CALL_GL_API(glUniform2f, location, v0, v1); +} +void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glUniform2fv, location, count, value); +} +void API_ENTRY(glUniform2i)(GLint location, GLint v0, GLint v1) { + CALL_GL_API(glUniform2i, location, v0, v1); +} +void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glUniform2iv, location, count, value); +} +void API_ENTRY(glUniform3f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { + CALL_GL_API(glUniform3f, location, v0, v1, v2); +} +void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glUniform3fv, location, count, value); +} +void API_ENTRY(glUniform3i)(GLint location, GLint v0, GLint v1, GLint v2) { + CALL_GL_API(glUniform3i, location, v0, v1, v2); +} +void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glUniform3iv, location, count, value); +} +void API_ENTRY(glUniform4f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { + CALL_GL_API(glUniform4f, location, v0, v1, v2, v3); +} +void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glUniform4fv, location, count, value); +} +void API_ENTRY(glUniform4i)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { + CALL_GL_API(glUniform4i, location, v0, v1, v2, v3); +} +void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glUniform4iv, location, count, value); +} +void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glUniformMatrix4fv, location, count, transpose, value); +} +void API_ENTRY(glUseProgram)(GLuint program) { + CALL_GL_API(glUseProgram, program); +} +void API_ENTRY(glValidateProgram)(GLuint program) { + CALL_GL_API(glValidateProgram, program); +} +void API_ENTRY(glVertexAttrib1f)(GLuint index, GLfloat x) { + CALL_GL_API(glVertexAttrib1f, index, x); +} +void API_ENTRY(glVertexAttrib1fv)(GLuint index, const GLfloat *v) { + CALL_GL_API(glVertexAttrib1fv, index, v); +} +void API_ENTRY(glVertexAttrib2f)(GLuint index, GLfloat x, GLfloat y) { + CALL_GL_API(glVertexAttrib2f, index, x, y); +} +void API_ENTRY(glVertexAttrib2fv)(GLuint index, const GLfloat *v) { + CALL_GL_API(glVertexAttrib2fv, index, v); +} +void API_ENTRY(glVertexAttrib3f)(GLuint index, GLfloat x, GLfloat y, GLfloat z) { + CALL_GL_API(glVertexAttrib3f, index, x, y, z); +} +void API_ENTRY(glVertexAttrib3fv)(GLuint index, const GLfloat *v) { + CALL_GL_API(glVertexAttrib3fv, index, v); +} +void API_ENTRY(glVertexAttrib4f)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { + CALL_GL_API(glVertexAttrib4f, index, x, y, z, w); +} +void API_ENTRY(glVertexAttrib4fv)(GLuint index, const GLfloat *v) { + CALL_GL_API(glVertexAttrib4fv, index, v); +} +void API_ENTRY(glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) { + CALL_GL_API(glVertexAttribPointer, index, size, type, normalized, stride, pointer); +} +void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glViewport, x, y, width, height); +} +void API_ENTRY(glReadBuffer)(GLenum src) { + CALL_GL_API(glReadBuffer, src); +} +void API_ENTRY(glDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices) { + CALL_GL_API(glDrawRangeElements, mode, start, end, count, type, indices); +} +void API_ENTRY(glTexImage3D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { + CALL_GL_API(glTexImage3D, target, level, internalformat, width, height, depth, border, format, type, pixels); +} +void API_ENTRY(glTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels) { + CALL_GL_API(glTexSubImage3D, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); +} +void API_ENTRY(glCopyTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glCopyTexSubImage3D, target, level, xoffset, yoffset, zoffset, x, y, width, height); +} +void API_ENTRY(glCompressedTexImage3D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) { + CALL_GL_API(glCompressedTexImage3D, target, level, internalformat, width, height, depth, border, imageSize, data); +} +void API_ENTRY(glCompressedTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) { + CALL_GL_API(glCompressedTexSubImage3D, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); +} +void API_ENTRY(glGenQueries)(GLsizei n, GLuint *ids) { + CALL_GL_API(glGenQueries, n, ids); +} +void API_ENTRY(glDeleteQueries)(GLsizei n, const GLuint *ids) { + CALL_GL_API(glDeleteQueries, n, ids); +} +GLboolean API_ENTRY(glIsQuery)(GLuint id) { + CALL_GL_API_RETURN(glIsQuery, id); +} +void API_ENTRY(glBeginQuery)(GLenum target, GLuint id) { + CALL_GL_API(glBeginQuery, target, id); +} +void API_ENTRY(glEndQuery)(GLenum target) { + CALL_GL_API(glEndQuery, target); +} +void API_ENTRY(glGetQueryiv)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetQueryiv, target, pname, params); +} +void API_ENTRY(glGetQueryObjectuiv)(GLuint id, GLenum pname, GLuint *params) { + CALL_GL_API(glGetQueryObjectuiv, id, pname, params); +} +GLboolean API_ENTRY(glUnmapBuffer)(GLenum target) { + CALL_GL_API_RETURN(glUnmapBuffer, target); +} +void API_ENTRY(glGetBufferPointerv)(GLenum target, GLenum pname, void **params) { + CALL_GL_API(glGetBufferPointerv, target, pname, params); +} +void API_ENTRY(glDrawBuffers)(GLsizei n, const GLenum *bufs) { + CALL_GL_API(glDrawBuffers, n, bufs); +} +void API_ENTRY(glUniformMatrix2x3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glUniformMatrix2x3fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix3x2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glUniformMatrix3x2fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix2x4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glUniformMatrix2x4fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix4x2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glUniformMatrix4x2fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix3x4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glUniformMatrix3x4fv, location, count, transpose, value); +} +void API_ENTRY(glUniformMatrix4x3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glUniformMatrix4x3fv, location, count, transpose, value); +} +void API_ENTRY(glBlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { + CALL_GL_API(glBlitFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); +} +void API_ENTRY(glRenderbufferStorageMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { + CALL_GL_API(glRenderbufferStorageMultisample, target, samples, internalformat, width, height); +} +void API_ENTRY(glFramebufferTextureLayer)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) { + CALL_GL_API(glFramebufferTextureLayer, target, attachment, texture, level, layer); +} +void * API_ENTRY(glMapBufferRange)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { + CALL_GL_API_RETURN(glMapBufferRange, target, offset, length, access); +} +void API_ENTRY(glFlushMappedBufferRange)(GLenum target, GLintptr offset, GLsizeiptr length) { + CALL_GL_API(glFlushMappedBufferRange, target, offset, length); +} +void API_ENTRY(glBindVertexArray)(GLuint array) { + CALL_GL_API(glBindVertexArray, array); +} +void API_ENTRY(glDeleteVertexArrays)(GLsizei n, const GLuint *arrays) { + CALL_GL_API(glDeleteVertexArrays, n, arrays); +} +void API_ENTRY(glGenVertexArrays)(GLsizei n, GLuint *arrays) { + CALL_GL_API(glGenVertexArrays, n, arrays); +} +GLboolean API_ENTRY(glIsVertexArray)(GLuint array) { + CALL_GL_API_RETURN(glIsVertexArray, array); +} +void API_ENTRY(glGetIntegeri_v)(GLenum target, GLuint index, GLint *data) { + CALL_GL_API(glGetIntegeri_v, target, index, data); +} +void API_ENTRY(glBeginTransformFeedback)(GLenum primitiveMode) { + CALL_GL_API(glBeginTransformFeedback, primitiveMode); +} +void API_ENTRY(glEndTransformFeedback)(void) { + CALL_GL_API(glEndTransformFeedback); +} +void API_ENTRY(glBindBufferRange)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) { + CALL_GL_API(glBindBufferRange, target, index, buffer, offset, size); +} +void API_ENTRY(glBindBufferBase)(GLenum target, GLuint index, GLuint buffer) { + CALL_GL_API(glBindBufferBase, target, index, buffer); +} +void API_ENTRY(glTransformFeedbackVaryings)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode) { + CALL_GL_API(glTransformFeedbackVaryings, program, count, varyings, bufferMode); +} +void API_ENTRY(glGetTransformFeedbackVarying)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) { + CALL_GL_API(glGetTransformFeedbackVarying, program, index, bufSize, length, size, type, name); +} +void API_ENTRY(glVertexAttribIPointer)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer) { + CALL_GL_API(glVertexAttribIPointer, index, size, type, stride, pointer); +} +void API_ENTRY(glGetVertexAttribIiv)(GLuint index, GLenum pname, GLint *params) { + CALL_GL_API(glGetVertexAttribIiv, index, pname, params); +} +void API_ENTRY(glGetVertexAttribIuiv)(GLuint index, GLenum pname, GLuint *params) { + CALL_GL_API(glGetVertexAttribIuiv, index, pname, params); +} +void API_ENTRY(glVertexAttribI4i)(GLuint index, GLint x, GLint y, GLint z, GLint w) { + CALL_GL_API(glVertexAttribI4i, index, x, y, z, w); +} +void API_ENTRY(glVertexAttribI4ui)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) { + CALL_GL_API(glVertexAttribI4ui, index, x, y, z, w); +} +void API_ENTRY(glVertexAttribI4iv)(GLuint index, const GLint *v) { + CALL_GL_API(glVertexAttribI4iv, index, v); +} +void API_ENTRY(glVertexAttribI4uiv)(GLuint index, const GLuint *v) { + CALL_GL_API(glVertexAttribI4uiv, index, v); +} +void API_ENTRY(glGetUniformuiv)(GLuint program, GLint location, GLuint *params) { + CALL_GL_API(glGetUniformuiv, program, location, params); +} +GLint API_ENTRY(glGetFragDataLocation)(GLuint program, const GLchar *name) { + CALL_GL_API_RETURN(glGetFragDataLocation, program, name); +} +void API_ENTRY(glUniform1ui)(GLint location, GLuint v0) { + CALL_GL_API(glUniform1ui, location, v0); +} +void API_ENTRY(glUniform2ui)(GLint location, GLuint v0, GLuint v1) { + CALL_GL_API(glUniform2ui, location, v0, v1); +} +void API_ENTRY(glUniform3ui)(GLint location, GLuint v0, GLuint v1, GLuint v2) { + CALL_GL_API(glUniform3ui, location, v0, v1, v2); +} +void API_ENTRY(glUniform4ui)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { + CALL_GL_API(glUniform4ui, location, v0, v1, v2, v3); +} +void API_ENTRY(glUniform1uiv)(GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glUniform1uiv, location, count, value); +} +void API_ENTRY(glUniform2uiv)(GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glUniform2uiv, location, count, value); +} +void API_ENTRY(glUniform3uiv)(GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glUniform3uiv, location, count, value); +} +void API_ENTRY(glUniform4uiv)(GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glUniform4uiv, location, count, value); +} +void API_ENTRY(glClearBufferiv)(GLenum buffer, GLint drawbuffer, const GLint *value) { + CALL_GL_API(glClearBufferiv, buffer, drawbuffer, value); +} +void API_ENTRY(glClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint *value) { + CALL_GL_API(glClearBufferuiv, buffer, drawbuffer, value); +} +void API_ENTRY(glClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat *value) { + CALL_GL_API(glClearBufferfv, buffer, drawbuffer, value); +} +void API_ENTRY(glClearBufferfi)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { + CALL_GL_API(glClearBufferfi, buffer, drawbuffer, depth, stencil); +} +const GLubyte * API_ENTRY(glGetStringi)(GLenum name, GLuint index) { + CALL_GL_API_RETURN(glGetStringi, name, index); +} +void API_ENTRY(glCopyBufferSubData)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { + CALL_GL_API(glCopyBufferSubData, readTarget, writeTarget, readOffset, writeOffset, size); +} +void API_ENTRY(glGetUniformIndices)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices) { + CALL_GL_API(glGetUniformIndices, program, uniformCount, uniformNames, uniformIndices); +} +void API_ENTRY(glGetActiveUniformsiv)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params) { + CALL_GL_API(glGetActiveUniformsiv, program, uniformCount, uniformIndices, pname, params); +} +GLuint API_ENTRY(glGetUniformBlockIndex)(GLuint program, const GLchar *uniformBlockName) { + CALL_GL_API_RETURN(glGetUniformBlockIndex, program, uniformBlockName); +} +void API_ENTRY(glGetActiveUniformBlockiv)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params) { + CALL_GL_API(glGetActiveUniformBlockiv, program, uniformBlockIndex, pname, params); +} +void API_ENTRY(glGetActiveUniformBlockName)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) { + CALL_GL_API(glGetActiveUniformBlockName, program, uniformBlockIndex, bufSize, length, uniformBlockName); +} +void API_ENTRY(glUniformBlockBinding)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { + CALL_GL_API(glUniformBlockBinding, program, uniformBlockIndex, uniformBlockBinding); +} +void API_ENTRY(glDrawArraysInstanced)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) { + CALL_GL_API(glDrawArraysInstanced, mode, first, count, instancecount); +} +void API_ENTRY(glDrawElementsInstanced)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount) { + CALL_GL_API(glDrawElementsInstanced, mode, count, type, indices, instancecount); +} +GLsync API_ENTRY(glFenceSync)(GLenum condition, GLbitfield flags) { + CALL_GL_API_RETURN(glFenceSync, condition, flags); +} +GLboolean API_ENTRY(glIsSync)(GLsync sync) { + CALL_GL_API_RETURN(glIsSync, sync); +} +void API_ENTRY(glDeleteSync)(GLsync sync) { + CALL_GL_API(glDeleteSync, sync); +} +GLenum API_ENTRY(glClientWaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeout) { + CALL_GL_API_RETURN(glClientWaitSync, sync, flags, timeout); +} +void API_ENTRY(glWaitSync)(GLsync sync, GLbitfield flags, GLuint64 timeout) { + CALL_GL_API(glWaitSync, sync, flags, timeout); +} +void API_ENTRY(glGetInteger64v)(GLenum pname, GLint64 *data) { + CALL_GL_API(glGetInteger64v, pname, data); +} +void API_ENTRY(glGetSynciv)(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) { + CALL_GL_API(glGetSynciv, sync, pname, bufSize, length, values); +} +void API_ENTRY(glGetInteger64i_v)(GLenum target, GLuint index, GLint64 *data) { + CALL_GL_API(glGetInteger64i_v, target, index, data); +} +void API_ENTRY(glGetBufferParameteri64v)(GLenum target, GLenum pname, GLint64 *params) { + CALL_GL_API(glGetBufferParameteri64v, target, pname, params); +} +void API_ENTRY(glGenSamplers)(GLsizei count, GLuint *samplers) { + CALL_GL_API(glGenSamplers, count, samplers); +} +void API_ENTRY(glDeleteSamplers)(GLsizei count, const GLuint *samplers) { + CALL_GL_API(glDeleteSamplers, count, samplers); +} +GLboolean API_ENTRY(glIsSampler)(GLuint sampler) { + CALL_GL_API_RETURN(glIsSampler, sampler); +} +void API_ENTRY(glBindSampler)(GLuint unit, GLuint sampler) { + CALL_GL_API(glBindSampler, unit, sampler); +} +void API_ENTRY(glSamplerParameteri)(GLuint sampler, GLenum pname, GLint param) { + CALL_GL_API(glSamplerParameteri, sampler, pname, param); +} +void API_ENTRY(glSamplerParameteriv)(GLuint sampler, GLenum pname, const GLint *param) { + CALL_GL_API(glSamplerParameteriv, sampler, pname, param); +} +void API_ENTRY(glSamplerParameterf)(GLuint sampler, GLenum pname, GLfloat param) { + CALL_GL_API(glSamplerParameterf, sampler, pname, param); +} +void API_ENTRY(glSamplerParameterfv)(GLuint sampler, GLenum pname, const GLfloat *param) { + CALL_GL_API(glSamplerParameterfv, sampler, pname, param); +} +void API_ENTRY(glGetSamplerParameteriv)(GLuint sampler, GLenum pname, GLint *params) { + CALL_GL_API(glGetSamplerParameteriv, sampler, pname, params); +} +void API_ENTRY(glGetSamplerParameterfv)(GLuint sampler, GLenum pname, GLfloat *params) { + CALL_GL_API(glGetSamplerParameterfv, sampler, pname, params); +} +void API_ENTRY(glVertexAttribDivisor)(GLuint index, GLuint divisor) { + CALL_GL_API(glVertexAttribDivisor, index, divisor); +} +void API_ENTRY(glBindTransformFeedback)(GLenum target, GLuint id) { + CALL_GL_API(glBindTransformFeedback, target, id); +} +void API_ENTRY(glDeleteTransformFeedbacks)(GLsizei n, const GLuint *ids) { + CALL_GL_API(glDeleteTransformFeedbacks, n, ids); +} +void API_ENTRY(glGenTransformFeedbacks)(GLsizei n, GLuint *ids) { + CALL_GL_API(glGenTransformFeedbacks, n, ids); +} +GLboolean API_ENTRY(glIsTransformFeedback)(GLuint id) { + CALL_GL_API_RETURN(glIsTransformFeedback, id); +} +void API_ENTRY(glPauseTransformFeedback)(void) { + CALL_GL_API(glPauseTransformFeedback); +} +void API_ENTRY(glResumeTransformFeedback)(void) { + CALL_GL_API(glResumeTransformFeedback); +} +void API_ENTRY(glGetProgramBinary)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) { + CALL_GL_API(glGetProgramBinary, program, bufSize, length, binaryFormat, binary); +} +void API_ENTRY(glProgramBinary)(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length) { + CALL_GL_API(glProgramBinary, program, binaryFormat, binary, length); +} +void API_ENTRY(glProgramParameteri)(GLuint program, GLenum pname, GLint value) { + CALL_GL_API(glProgramParameteri, program, pname, value); +} +void API_ENTRY(glInvalidateFramebuffer)(GLenum target, GLsizei numAttachments, const GLenum *attachments) { + CALL_GL_API(glInvalidateFramebuffer, target, numAttachments, attachments); +} +void API_ENTRY(glInvalidateSubFramebuffer)(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glInvalidateSubFramebuffer, target, numAttachments, attachments, x, y, width, height); +} +void API_ENTRY(glTexStorage2D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { + CALL_GL_API(glTexStorage2D, target, levels, internalformat, width, height); +} +void API_ENTRY(glTexStorage3D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { + CALL_GL_API(glTexStorage3D, target, levels, internalformat, width, height, depth); +} +void API_ENTRY(glGetInternalformativ)(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) { + CALL_GL_API(glGetInternalformativ, target, internalformat, pname, bufSize, params); +} +void API_ENTRY(glDispatchCompute)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) { + CALL_GL_API(glDispatchCompute, num_groups_x, num_groups_y, num_groups_z); +} +void API_ENTRY(glDispatchComputeIndirect)(GLintptr indirect) { + CALL_GL_API(glDispatchComputeIndirect, indirect); +} +void API_ENTRY(glDrawArraysIndirect)(GLenum mode, const void *indirect) { + CALL_GL_API(glDrawArraysIndirect, mode, indirect); +} +void API_ENTRY(glDrawElementsIndirect)(GLenum mode, GLenum type, const void *indirect) { + CALL_GL_API(glDrawElementsIndirect, mode, type, indirect); +} +void API_ENTRY(glFramebufferParameteri)(GLenum target, GLenum pname, GLint param) { + CALL_GL_API(glFramebufferParameteri, target, pname, param); +} +void API_ENTRY(glGetFramebufferParameteriv)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetFramebufferParameteriv, target, pname, params); +} +void API_ENTRY(glGetProgramInterfaceiv)(GLuint program, GLenum programInterface, GLenum pname, GLint *params) { + CALL_GL_API(glGetProgramInterfaceiv, program, programInterface, pname, params); +} +GLuint API_ENTRY(glGetProgramResourceIndex)(GLuint program, GLenum programInterface, const GLchar *name) { + CALL_GL_API_RETURN(glGetProgramResourceIndex, program, programInterface, name); +} +void API_ENTRY(glGetProgramResourceName)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) { + CALL_GL_API(glGetProgramResourceName, program, programInterface, index, bufSize, length, name); +} +void API_ENTRY(glGetProgramResourceiv)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params) { + CALL_GL_API(glGetProgramResourceiv, program, programInterface, index, propCount, props, bufSize, length, params); +} +GLint API_ENTRY(glGetProgramResourceLocation)(GLuint program, GLenum programInterface, const GLchar *name) { + CALL_GL_API_RETURN(glGetProgramResourceLocation, program, programInterface, name); +} +void API_ENTRY(glUseProgramStages)(GLuint pipeline, GLbitfield stages, GLuint program) { + CALL_GL_API(glUseProgramStages, pipeline, stages, program); +} +void API_ENTRY(glActiveShaderProgram)(GLuint pipeline, GLuint program) { + CALL_GL_API(glActiveShaderProgram, pipeline, program); +} +GLuint API_ENTRY(glCreateShaderProgramv)(GLenum type, GLsizei count, const GLchar *const*strings) { + CALL_GL_API_RETURN(glCreateShaderProgramv, type, count, strings); +} +void API_ENTRY(glBindProgramPipeline)(GLuint pipeline) { + CALL_GL_API(glBindProgramPipeline, pipeline); +} +void API_ENTRY(glDeleteProgramPipelines)(GLsizei n, const GLuint *pipelines) { + CALL_GL_API(glDeleteProgramPipelines, n, pipelines); +} +void API_ENTRY(glGenProgramPipelines)(GLsizei n, GLuint *pipelines) { + CALL_GL_API(glGenProgramPipelines, n, pipelines); +} +GLboolean API_ENTRY(glIsProgramPipeline)(GLuint pipeline) { + CALL_GL_API_RETURN(glIsProgramPipeline, pipeline); +} +void API_ENTRY(glGetProgramPipelineiv)(GLuint pipeline, GLenum pname, GLint *params) { + CALL_GL_API(glGetProgramPipelineiv, pipeline, pname, params); +} +void API_ENTRY(glProgramUniform1i)(GLuint program, GLint location, GLint v0) { + CALL_GL_API(glProgramUniform1i, program, location, v0); +} +void API_ENTRY(glProgramUniform2i)(GLuint program, GLint location, GLint v0, GLint v1) { + CALL_GL_API(glProgramUniform2i, program, location, v0, v1); +} +void API_ENTRY(glProgramUniform3i)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2) { + CALL_GL_API(glProgramUniform3i, program, location, v0, v1, v2); +} +void API_ENTRY(glProgramUniform4i)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { + CALL_GL_API(glProgramUniform4i, program, location, v0, v1, v2, v3); +} +void API_ENTRY(glProgramUniform1ui)(GLuint program, GLint location, GLuint v0) { + CALL_GL_API(glProgramUniform1ui, program, location, v0); +} +void API_ENTRY(glProgramUniform2ui)(GLuint program, GLint location, GLuint v0, GLuint v1) { + CALL_GL_API(glProgramUniform2ui, program, location, v0, v1); +} +void API_ENTRY(glProgramUniform3ui)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) { + CALL_GL_API(glProgramUniform3ui, program, location, v0, v1, v2); +} +void API_ENTRY(glProgramUniform4ui)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { + CALL_GL_API(glProgramUniform4ui, program, location, v0, v1, v2, v3); +} +void API_ENTRY(glProgramUniform1f)(GLuint program, GLint location, GLfloat v0) { + CALL_GL_API(glProgramUniform1f, program, location, v0); +} +void API_ENTRY(glProgramUniform2f)(GLuint program, GLint location, GLfloat v0, GLfloat v1) { + CALL_GL_API(glProgramUniform2f, program, location, v0, v1); +} +void API_ENTRY(glProgramUniform3f)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { + CALL_GL_API(glProgramUniform3f, program, location, v0, v1, v2); +} +void API_ENTRY(glProgramUniform4f)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { + CALL_GL_API(glProgramUniform4f, program, location, v0, v1, v2, v3); +} +void API_ENTRY(glProgramUniform1iv)(GLuint program, GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glProgramUniform1iv, program, location, count, value); +} +void API_ENTRY(glProgramUniform2iv)(GLuint program, GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glProgramUniform2iv, program, location, count, value); +} +void API_ENTRY(glProgramUniform3iv)(GLuint program, GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glProgramUniform3iv, program, location, count, value); +} +void API_ENTRY(glProgramUniform4iv)(GLuint program, GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glProgramUniform4iv, program, location, count, value); +} +void API_ENTRY(glProgramUniform1uiv)(GLuint program, GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glProgramUniform1uiv, program, location, count, value); +} +void API_ENTRY(glProgramUniform2uiv)(GLuint program, GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glProgramUniform2uiv, program, location, count, value); +} +void API_ENTRY(glProgramUniform3uiv)(GLuint program, GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glProgramUniform3uiv, program, location, count, value); +} +void API_ENTRY(glProgramUniform4uiv)(GLuint program, GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glProgramUniform4uiv, program, location, count, value); +} +void API_ENTRY(glProgramUniform1fv)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glProgramUniform1fv, program, location, count, value); +} +void API_ENTRY(glProgramUniform2fv)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glProgramUniform2fv, program, location, count, value); +} +void API_ENTRY(glProgramUniform3fv)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glProgramUniform3fv, program, location, count, value); +} +void API_ENTRY(glProgramUniform4fv)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glProgramUniform4fv, program, location, count, value); +} +void API_ENTRY(glProgramUniformMatrix2fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix2fv, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix3fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix3fv, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix4fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix4fv, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix2x3fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix2x3fv, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix3x2fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix3x2fv, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix2x4fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix2x4fv, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix4x2fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix4x2fv, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix3x4fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix3x4fv, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix4x3fv)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix4x3fv, program, location, count, transpose, value); +} +void API_ENTRY(glValidateProgramPipeline)(GLuint pipeline) { + CALL_GL_API(glValidateProgramPipeline, pipeline); +} +void API_ENTRY(glGetProgramPipelineInfoLog)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { + CALL_GL_API(glGetProgramPipelineInfoLog, pipeline, bufSize, length, infoLog); +} +void API_ENTRY(glBindImageTexture)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) { + CALL_GL_API(glBindImageTexture, unit, texture, level, layered, layer, access, format); +} +void API_ENTRY(glGetBooleani_v)(GLenum target, GLuint index, GLboolean *data) { + CALL_GL_API(glGetBooleani_v, target, index, data); +} +void API_ENTRY(glMemoryBarrier)(GLbitfield barriers) { + CALL_GL_API(glMemoryBarrier, barriers); +} +void API_ENTRY(glMemoryBarrierByRegion)(GLbitfield barriers) { + CALL_GL_API(glMemoryBarrierByRegion, barriers); +} +void API_ENTRY(glTexStorage2DMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) { + CALL_GL_API(glTexStorage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations); +} +void API_ENTRY(glGetMultisamplefv)(GLenum pname, GLuint index, GLfloat *val) { + CALL_GL_API(glGetMultisamplefv, pname, index, val); +} +void API_ENTRY(glSampleMaski)(GLuint maskNumber, GLbitfield mask) { + CALL_GL_API(glSampleMaski, maskNumber, mask); +} +void API_ENTRY(glGetTexLevelParameteriv)(GLenum target, GLint level, GLenum pname, GLint *params) { + CALL_GL_API(glGetTexLevelParameteriv, target, level, pname, params); +} +void API_ENTRY(glGetTexLevelParameterfv)(GLenum target, GLint level, GLenum pname, GLfloat *params) { + CALL_GL_API(glGetTexLevelParameterfv, target, level, pname, params); +} +void API_ENTRY(glBindVertexBuffer)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) { + CALL_GL_API(glBindVertexBuffer, bindingindex, buffer, offset, stride); +} +void API_ENTRY(glVertexAttribFormat)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) { + CALL_GL_API(glVertexAttribFormat, attribindex, size, type, normalized, relativeoffset); +} +void API_ENTRY(glVertexAttribIFormat)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) { + CALL_GL_API(glVertexAttribIFormat, attribindex, size, type, relativeoffset); +} +void API_ENTRY(glVertexAttribBinding)(GLuint attribindex, GLuint bindingindex) { + CALL_GL_API(glVertexAttribBinding, attribindex, bindingindex); +} +void API_ENTRY(glVertexBindingDivisor)(GLuint bindingindex, GLuint divisor) { + CALL_GL_API(glVertexBindingDivisor, bindingindex, divisor); +} +void API_ENTRY(glBlendBarrier)(void) { + CALL_GL_API(glBlendBarrier); +} +void API_ENTRY(glCopyImageSubData)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { + CALL_GL_API(glCopyImageSubData, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); +} +void API_ENTRY(glDebugMessageControl)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled) { + CALL_GL_API(glDebugMessageControl, source, type, severity, count, ids, enabled); +} +void API_ENTRY(glDebugMessageInsert)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf) { + CALL_GL_API(glDebugMessageInsert, source, type, id, severity, length, buf); +} +void API_ENTRY(glDebugMessageCallback)(GLDEBUGPROC callback, const void *userParam) { + CALL_GL_API(glDebugMessageCallback, callback, userParam); +} +GLuint API_ENTRY(glGetDebugMessageLog)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog) { + CALL_GL_API_RETURN(glGetDebugMessageLog, count, bufSize, sources, types, ids, severities, lengths, messageLog); +} +void API_ENTRY(glPushDebugGroup)(GLenum source, GLuint id, GLsizei length, const GLchar *message) { + CALL_GL_API(glPushDebugGroup, source, id, length, message); +} +void API_ENTRY(glPopDebugGroup)(void) { + CALL_GL_API(glPopDebugGroup); +} +void API_ENTRY(glObjectLabel)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label) { + CALL_GL_API(glObjectLabel, identifier, name, length, label); +} +void API_ENTRY(glGetObjectLabel)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label) { + CALL_GL_API(glGetObjectLabel, identifier, name, bufSize, length, label); +} +void API_ENTRY(glObjectPtrLabel)(const void *ptr, GLsizei length, const GLchar *label) { + CALL_GL_API(glObjectPtrLabel, ptr, length, label); +} +void API_ENTRY(glGetObjectPtrLabel)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) { + CALL_GL_API(glGetObjectPtrLabel, ptr, bufSize, length, label); +} +void API_ENTRY(glGetPointerv)(GLenum pname, void **params) { + CALL_GL_API(glGetPointerv, pname, params); +} +void API_ENTRY(glEnablei)(GLenum target, GLuint index) { + CALL_GL_API(glEnablei, target, index); +} +void API_ENTRY(glDisablei)(GLenum target, GLuint index) { + CALL_GL_API(glDisablei, target, index); +} +void API_ENTRY(glBlendEquationi)(GLuint buf, GLenum mode) { + CALL_GL_API(glBlendEquationi, buf, mode); +} +void API_ENTRY(glBlendEquationSeparatei)(GLuint buf, GLenum modeRGB, GLenum modeAlpha) { + CALL_GL_API(glBlendEquationSeparatei, buf, modeRGB, modeAlpha); +} +void API_ENTRY(glBlendFunci)(GLuint buf, GLenum src, GLenum dst) { + CALL_GL_API(glBlendFunci, buf, src, dst); +} +void API_ENTRY(glBlendFuncSeparatei)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { + CALL_GL_API(glBlendFuncSeparatei, buf, srcRGB, dstRGB, srcAlpha, dstAlpha); +} +void API_ENTRY(glColorMaski)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { + CALL_GL_API(glColorMaski, index, r, g, b, a); +} +GLboolean API_ENTRY(glIsEnabledi)(GLenum target, GLuint index) { + CALL_GL_API_RETURN(glIsEnabledi, target, index); +} +void API_ENTRY(glDrawElementsBaseVertex)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) { + CALL_GL_API(glDrawElementsBaseVertex, mode, count, type, indices, basevertex); +} +void API_ENTRY(glDrawRangeElementsBaseVertex)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) { + CALL_GL_API(glDrawRangeElementsBaseVertex, mode, start, end, count, type, indices, basevertex); +} +void API_ENTRY(glDrawElementsInstancedBaseVertex)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) { + CALL_GL_API(glDrawElementsInstancedBaseVertex, mode, count, type, indices, instancecount, basevertex); +} +void API_ENTRY(glFramebufferTexture)(GLenum target, GLenum attachment, GLuint texture, GLint level) { + CALL_GL_API(glFramebufferTexture, target, attachment, texture, level); +} +void API_ENTRY(glPrimitiveBoundingBox)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) { + CALL_GL_API(glPrimitiveBoundingBox, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW); +} +GLenum API_ENTRY(glGetGraphicsResetStatus)(void) { + CALL_GL_API_RETURN(glGetGraphicsResetStatus); +} +void API_ENTRY(glReadnPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) { + CALL_GL_API(glReadnPixels, x, y, width, height, format, type, bufSize, data); +} +void API_ENTRY(glGetnUniformfv)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params) { + CALL_GL_API(glGetnUniformfv, program, location, bufSize, params); +} +void API_ENTRY(glGetnUniformiv)(GLuint program, GLint location, GLsizei bufSize, GLint *params) { + CALL_GL_API(glGetnUniformiv, program, location, bufSize, params); +} +void API_ENTRY(glGetnUniformuiv)(GLuint program, GLint location, GLsizei bufSize, GLuint *params) { + CALL_GL_API(glGetnUniformuiv, program, location, bufSize, params); +} +void API_ENTRY(glMinSampleShading)(GLfloat value) { + CALL_GL_API(glMinSampleShading, value); +} +void API_ENTRY(glPatchParameteri)(GLenum pname, GLint value) { + CALL_GL_API(glPatchParameteri, pname, value); +} +void API_ENTRY(glTexParameterIiv)(GLenum target, GLenum pname, const GLint *params) { + CALL_GL_API(glTexParameterIiv, target, pname, params); +} +void API_ENTRY(glTexParameterIuiv)(GLenum target, GLenum pname, const GLuint *params) { + CALL_GL_API(glTexParameterIuiv, target, pname, params); +} +void API_ENTRY(glGetTexParameterIiv)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetTexParameterIiv, target, pname, params); +} +void API_ENTRY(glGetTexParameterIuiv)(GLenum target, GLenum pname, GLuint *params) { + CALL_GL_API(glGetTexParameterIuiv, target, pname, params); +} +void API_ENTRY(glSamplerParameterIiv)(GLuint sampler, GLenum pname, const GLint *param) { + CALL_GL_API(glSamplerParameterIiv, sampler, pname, param); +} +void API_ENTRY(glSamplerParameterIuiv)(GLuint sampler, GLenum pname, const GLuint *param) { + CALL_GL_API(glSamplerParameterIuiv, sampler, pname, param); +} +void API_ENTRY(glGetSamplerParameterIiv)(GLuint sampler, GLenum pname, GLint *params) { + CALL_GL_API(glGetSamplerParameterIiv, sampler, pname, params); +} +void API_ENTRY(glGetSamplerParameterIuiv)(GLuint sampler, GLenum pname, GLuint *params) { + CALL_GL_API(glGetSamplerParameterIuiv, sampler, pname, params); +} +void API_ENTRY(glTexBuffer)(GLenum target, GLenum internalformat, GLuint buffer) { + CALL_GL_API(glTexBuffer, target, internalformat, buffer); +} +void API_ENTRY(glTexBufferRange)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) { + CALL_GL_API(glTexBufferRange, target, internalformat, buffer, offset, size); +} +void API_ENTRY(glTexStorage3DMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) { + CALL_GL_API(glTexStorage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations); +} +void API_ENTRY(glBlendBarrierKHR)(void) { + CALL_GL_API(glBlendBarrierKHR); +} +void API_ENTRY(glDebugMessageControlKHR)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled) { + CALL_GL_API(glDebugMessageControlKHR, source, type, severity, count, ids, enabled); +} +void API_ENTRY(glDebugMessageInsertKHR)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf) { + CALL_GL_API(glDebugMessageInsertKHR, source, type, id, severity, length, buf); +} +void API_ENTRY(glDebugMessageCallbackKHR)(GLDEBUGPROCKHR callback, const void *userParam) { + CALL_GL_API(glDebugMessageCallbackKHR, callback, userParam); +} +GLuint API_ENTRY(glGetDebugMessageLogKHR)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog) { + CALL_GL_API_RETURN(glGetDebugMessageLogKHR, count, bufSize, sources, types, ids, severities, lengths, messageLog); +} +void API_ENTRY(glPushDebugGroupKHR)(GLenum source, GLuint id, GLsizei length, const GLchar *message) { + CALL_GL_API(glPushDebugGroupKHR, source, id, length, message); +} +void API_ENTRY(glPopDebugGroupKHR)(void) { + CALL_GL_API(glPopDebugGroupKHR); +} +void API_ENTRY(glObjectLabelKHR)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label) { + CALL_GL_API(glObjectLabelKHR, identifier, name, length, label); +} +void API_ENTRY(glGetObjectLabelKHR)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label) { + CALL_GL_API(glGetObjectLabelKHR, identifier, name, bufSize, length, label); +} +void API_ENTRY(glObjectPtrLabelKHR)(const void *ptr, GLsizei length, const GLchar *label) { + CALL_GL_API(glObjectPtrLabelKHR, ptr, length, label); +} +void API_ENTRY(glGetObjectPtrLabelKHR)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label) { + CALL_GL_API(glGetObjectPtrLabelKHR, ptr, bufSize, length, label); +} +void API_ENTRY(glGetPointervKHR)(GLenum pname, void **params) { + CALL_GL_API(glGetPointervKHR, pname, params); +} +GLenum API_ENTRY(glGetGraphicsResetStatusKHR)(void) { + CALL_GL_API_RETURN(glGetGraphicsResetStatusKHR); +} +void API_ENTRY(glReadnPixelsKHR)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) { + CALL_GL_API(glReadnPixelsKHR, x, y, width, height, format, type, bufSize, data); +} +void API_ENTRY(glGetnUniformfvKHR)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params) { + CALL_GL_API(glGetnUniformfvKHR, program, location, bufSize, params); +} +void API_ENTRY(glGetnUniformivKHR)(GLuint program, GLint location, GLsizei bufSize, GLint *params) { + CALL_GL_API(glGetnUniformivKHR, program, location, bufSize, params); +} +void API_ENTRY(glGetnUniformuivKHR)(GLuint program, GLint location, GLsizei bufSize, GLuint *params) { + CALL_GL_API(glGetnUniformuivKHR, program, location, bufSize, params); +} +void API_ENTRY(glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) { + CALL_GL_API(glEGLImageTargetTexture2DOES, target, image); +} +void API_ENTRY(glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) { + CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image); +} +void API_ENTRY(glCopyImageSubDataOES)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { + CALL_GL_API(glCopyImageSubDataOES, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); +} +void API_ENTRY(glEnableiOES)(GLenum target, GLuint index) { + CALL_GL_API(glEnableiOES, target, index); +} +void API_ENTRY(glDisableiOES)(GLenum target, GLuint index) { + CALL_GL_API(glDisableiOES, target, index); +} +void API_ENTRY(glBlendEquationiOES)(GLuint buf, GLenum mode) { + CALL_GL_API(glBlendEquationiOES, buf, mode); +} +void API_ENTRY(glBlendEquationSeparateiOES)(GLuint buf, GLenum modeRGB, GLenum modeAlpha) { + CALL_GL_API(glBlendEquationSeparateiOES, buf, modeRGB, modeAlpha); +} +void API_ENTRY(glBlendFunciOES)(GLuint buf, GLenum src, GLenum dst) { + CALL_GL_API(glBlendFunciOES, buf, src, dst); +} +void API_ENTRY(glBlendFuncSeparateiOES)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { + CALL_GL_API(glBlendFuncSeparateiOES, buf, srcRGB, dstRGB, srcAlpha, dstAlpha); +} +void API_ENTRY(glColorMaskiOES)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { + CALL_GL_API(glColorMaskiOES, index, r, g, b, a); +} +GLboolean API_ENTRY(glIsEnablediOES)(GLenum target, GLuint index) { + CALL_GL_API_RETURN(glIsEnablediOES, target, index); +} +void API_ENTRY(glDrawElementsBaseVertexOES)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) { + CALL_GL_API(glDrawElementsBaseVertexOES, mode, count, type, indices, basevertex); +} +void API_ENTRY(glDrawRangeElementsBaseVertexOES)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) { + CALL_GL_API(glDrawRangeElementsBaseVertexOES, mode, start, end, count, type, indices, basevertex); +} +void API_ENTRY(glDrawElementsInstancedBaseVertexOES)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) { + CALL_GL_API(glDrawElementsInstancedBaseVertexOES, mode, count, type, indices, instancecount, basevertex); +} +void API_ENTRY(glMultiDrawElementsBaseVertexOES)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) { + CALL_GL_API(glMultiDrawElementsBaseVertexOES, mode, count, type, indices, primcount, basevertex); +} +void API_ENTRY(glFramebufferTextureOES)(GLenum target, GLenum attachment, GLuint texture, GLint level) { + CALL_GL_API(glFramebufferTextureOES, target, attachment, texture, level); +} +void API_ENTRY(glGetProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) { + CALL_GL_API(glGetProgramBinaryOES, program, bufSize, length, binaryFormat, binary); +} +void API_ENTRY(glProgramBinaryOES)(GLuint program, GLenum binaryFormat, const void *binary, GLint length) { + CALL_GL_API(glProgramBinaryOES, program, binaryFormat, binary, length); +} +void * API_ENTRY(glMapBufferOES)(GLenum target, GLenum access) { + CALL_GL_API_RETURN(glMapBufferOES, target, access); +} +GLboolean API_ENTRY(glUnmapBufferOES)(GLenum target) { + CALL_GL_API_RETURN(glUnmapBufferOES, target); +} +void API_ENTRY(glGetBufferPointervOES)(GLenum target, GLenum pname, void **params) { + CALL_GL_API(glGetBufferPointervOES, target, pname, params); +} +void API_ENTRY(glPrimitiveBoundingBoxOES)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) { + CALL_GL_API(glPrimitiveBoundingBoxOES, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW); +} +void API_ENTRY(glMinSampleShadingOES)(GLfloat value) { + CALL_GL_API(glMinSampleShadingOES, value); +} +void API_ENTRY(glPatchParameteriOES)(GLenum pname, GLint value) { + CALL_GL_API(glPatchParameteriOES, pname, value); +} +void API_ENTRY(glTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels) { + CALL_GL_API(glTexImage3DOES, target, level, internalformat, width, height, depth, border, format, type, pixels); +} +void API_ENTRY(glTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels) { + CALL_GL_API(glTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); +} +void API_ENTRY(glCopyTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) { + CALL_GL_API(glCopyTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, x, y, width, height); +} +void API_ENTRY(glCompressedTexImage3DOES)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) { + CALL_GL_API(glCompressedTexImage3DOES, target, level, internalformat, width, height, depth, border, imageSize, data); +} +void API_ENTRY(glCompressedTexSubImage3DOES)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) { + CALL_GL_API(glCompressedTexSubImage3DOES, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); +} +void API_ENTRY(glFramebufferTexture3DOES)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) { + CALL_GL_API(glFramebufferTexture3DOES, target, attachment, textarget, texture, level, zoffset); +} +void API_ENTRY(glTexParameterIivOES)(GLenum target, GLenum pname, const GLint *params) { + CALL_GL_API(glTexParameterIivOES, target, pname, params); +} +void API_ENTRY(glTexParameterIuivOES)(GLenum target, GLenum pname, const GLuint *params) { + CALL_GL_API(glTexParameterIuivOES, target, pname, params); +} +void API_ENTRY(glGetTexParameterIivOES)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetTexParameterIivOES, target, pname, params); +} +void API_ENTRY(glGetTexParameterIuivOES)(GLenum target, GLenum pname, GLuint *params) { + CALL_GL_API(glGetTexParameterIuivOES, target, pname, params); +} +void API_ENTRY(glSamplerParameterIivOES)(GLuint sampler, GLenum pname, const GLint *param) { + CALL_GL_API(glSamplerParameterIivOES, sampler, pname, param); +} +void API_ENTRY(glSamplerParameterIuivOES)(GLuint sampler, GLenum pname, const GLuint *param) { + CALL_GL_API(glSamplerParameterIuivOES, sampler, pname, param); +} +void API_ENTRY(glGetSamplerParameterIivOES)(GLuint sampler, GLenum pname, GLint *params) { + CALL_GL_API(glGetSamplerParameterIivOES, sampler, pname, params); +} +void API_ENTRY(glGetSamplerParameterIuivOES)(GLuint sampler, GLenum pname, GLuint *params) { + CALL_GL_API(glGetSamplerParameterIuivOES, sampler, pname, params); +} +void API_ENTRY(glTexBufferOES)(GLenum target, GLenum internalformat, GLuint buffer) { + CALL_GL_API(glTexBufferOES, target, internalformat, buffer); +} +void API_ENTRY(glTexBufferRangeOES)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) { + CALL_GL_API(glTexBufferRangeOES, target, internalformat, buffer, offset, size); +} +void API_ENTRY(glTexStorage3DMultisampleOES)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) { + CALL_GL_API(glTexStorage3DMultisampleOES, target, samples, internalformat, width, height, depth, fixedsamplelocations); +} +void API_ENTRY(glTextureViewOES)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) { + CALL_GL_API(glTextureViewOES, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers); +} +void API_ENTRY(glBindVertexArrayOES)(GLuint array) { + CALL_GL_API(glBindVertexArrayOES, array); +} +void API_ENTRY(glDeleteVertexArraysOES)(GLsizei n, const GLuint *arrays) { + CALL_GL_API(glDeleteVertexArraysOES, n, arrays); +} +void API_ENTRY(glGenVertexArraysOES)(GLsizei n, GLuint *arrays) { + CALL_GL_API(glGenVertexArraysOES, n, arrays); +} +GLboolean API_ENTRY(glIsVertexArrayOES)(GLuint array) { + CALL_GL_API_RETURN(glIsVertexArrayOES, array); +} +void API_ENTRY(glDrawArraysInstancedBaseInstanceEXT)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance) { + CALL_GL_API(glDrawArraysInstancedBaseInstanceEXT, mode, first, count, instancecount, baseinstance); +} +void API_ENTRY(glDrawElementsInstancedBaseInstanceEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance) { + CALL_GL_API(glDrawElementsInstancedBaseInstanceEXT, mode, count, type, indices, instancecount, baseinstance); +} +void API_ENTRY(glDrawElementsInstancedBaseVertexBaseInstanceEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance) { + CALL_GL_API(glDrawElementsInstancedBaseVertexBaseInstanceEXT, mode, count, type, indices, instancecount, basevertex, baseinstance); +} +void API_ENTRY(glBindFragDataLocationIndexedEXT)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name) { + CALL_GL_API(glBindFragDataLocationIndexedEXT, program, colorNumber, index, name); +} +void API_ENTRY(glBindFragDataLocationEXT)(GLuint program, GLuint color, const GLchar *name) { + CALL_GL_API(glBindFragDataLocationEXT, program, color, name); +} +GLint API_ENTRY(glGetProgramResourceLocationIndexEXT)(GLuint program, GLenum programInterface, const GLchar *name) { + CALL_GL_API_RETURN(glGetProgramResourceLocationIndexEXT, program, programInterface, name); +} +GLint API_ENTRY(glGetFragDataIndexEXT)(GLuint program, const GLchar *name) { + CALL_GL_API_RETURN(glGetFragDataIndexEXT, program, name); +} +void API_ENTRY(glBufferStorageEXT)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags) { + CALL_GL_API(glBufferStorageEXT, target, size, data, flags); +} +void API_ENTRY(glCopyImageSubDataEXT)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { + CALL_GL_API(glCopyImageSubDataEXT, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); +} +void API_ENTRY(glLabelObjectEXT)(GLenum type, GLuint object, GLsizei length, const GLchar *label) { + CALL_GL_API(glLabelObjectEXT, type, object, length, label); +} +void API_ENTRY(glGetObjectLabelEXT)(GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label) { + CALL_GL_API(glGetObjectLabelEXT, type, object, bufSize, length, label); +} +void API_ENTRY(glInsertEventMarkerEXT)(GLsizei length, const GLchar *marker) { + CALL_GL_API(glInsertEventMarkerEXT, length, marker); +} +void API_ENTRY(glPushGroupMarkerEXT)(GLsizei length, const GLchar *marker) { + CALL_GL_API(glPushGroupMarkerEXT, length, marker); +} +void API_ENTRY(glPopGroupMarkerEXT)(void) { + CALL_GL_API(glPopGroupMarkerEXT); +} +void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) { + CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments); +} +void API_ENTRY(glGenQueriesEXT)(GLsizei n, GLuint *ids) { + CALL_GL_API(glGenQueriesEXT, n, ids); +} +void API_ENTRY(glDeleteQueriesEXT)(GLsizei n, const GLuint *ids) { + CALL_GL_API(glDeleteQueriesEXT, n, ids); +} +GLboolean API_ENTRY(glIsQueryEXT)(GLuint id) { + CALL_GL_API_RETURN(glIsQueryEXT, id); +} +void API_ENTRY(glBeginQueryEXT)(GLenum target, GLuint id) { + CALL_GL_API(glBeginQueryEXT, target, id); +} +void API_ENTRY(glEndQueryEXT)(GLenum target) { + CALL_GL_API(glEndQueryEXT, target); +} +void API_ENTRY(glQueryCounterEXT)(GLuint id, GLenum target) { + CALL_GL_API(glQueryCounterEXT, id, target); +} +void API_ENTRY(glGetQueryivEXT)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetQueryivEXT, target, pname, params); +} +void API_ENTRY(glGetQueryObjectivEXT)(GLuint id, GLenum pname, GLint *params) { + CALL_GL_API(glGetQueryObjectivEXT, id, pname, params); +} +void API_ENTRY(glGetQueryObjectuivEXT)(GLuint id, GLenum pname, GLuint *params) { + CALL_GL_API(glGetQueryObjectuivEXT, id, pname, params); +} +void API_ENTRY(glGetQueryObjecti64vEXT)(GLuint id, GLenum pname, GLint64 *params) { + CALL_GL_API(glGetQueryObjecti64vEXT, id, pname, params); +} +void API_ENTRY(glGetQueryObjectui64vEXT)(GLuint id, GLenum pname, GLuint64 *params) { + CALL_GL_API(glGetQueryObjectui64vEXT, id, pname, params); +} +void API_ENTRY(glDrawBuffersEXT)(GLsizei n, const GLenum *bufs) { + CALL_GL_API(glDrawBuffersEXT, n, bufs); +} +void API_ENTRY(glEnableiEXT)(GLenum target, GLuint index) { + CALL_GL_API(glEnableiEXT, target, index); +} +void API_ENTRY(glDisableiEXT)(GLenum target, GLuint index) { + CALL_GL_API(glDisableiEXT, target, index); +} +void API_ENTRY(glBlendEquationiEXT)(GLuint buf, GLenum mode) { + CALL_GL_API(glBlendEquationiEXT, buf, mode); +} +void API_ENTRY(glBlendEquationSeparateiEXT)(GLuint buf, GLenum modeRGB, GLenum modeAlpha) { + CALL_GL_API(glBlendEquationSeparateiEXT, buf, modeRGB, modeAlpha); +} +void API_ENTRY(glBlendFunciEXT)(GLuint buf, GLenum src, GLenum dst) { + CALL_GL_API(glBlendFunciEXT, buf, src, dst); +} +void API_ENTRY(glBlendFuncSeparateiEXT)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { + CALL_GL_API(glBlendFuncSeparateiEXT, buf, srcRGB, dstRGB, srcAlpha, dstAlpha); +} +void API_ENTRY(glColorMaskiEXT)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { + CALL_GL_API(glColorMaskiEXT, index, r, g, b, a); +} +GLboolean API_ENTRY(glIsEnablediEXT)(GLenum target, GLuint index) { + CALL_GL_API_RETURN(glIsEnablediEXT, target, index); +} +void API_ENTRY(glDrawElementsBaseVertexEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex) { + CALL_GL_API(glDrawElementsBaseVertexEXT, mode, count, type, indices, basevertex); +} +void API_ENTRY(glDrawRangeElementsBaseVertexEXT)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex) { + CALL_GL_API(glDrawRangeElementsBaseVertexEXT, mode, start, end, count, type, indices, basevertex); +} +void API_ENTRY(glDrawElementsInstancedBaseVertexEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex) { + CALL_GL_API(glDrawElementsInstancedBaseVertexEXT, mode, count, type, indices, instancecount, basevertex); +} +void API_ENTRY(glMultiDrawElementsBaseVertexEXT)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex) { + CALL_GL_API(glMultiDrawElementsBaseVertexEXT, mode, count, type, indices, primcount, basevertex); +} +void API_ENTRY(glDrawArraysInstancedEXT)(GLenum mode, GLint start, GLsizei count, GLsizei primcount) { + CALL_GL_API(glDrawArraysInstancedEXT, mode, start, count, primcount); +} +void API_ENTRY(glDrawElementsInstancedEXT)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) { + CALL_GL_API(glDrawElementsInstancedEXT, mode, count, type, indices, primcount); +} +void API_ENTRY(glFramebufferTextureEXT)(GLenum target, GLenum attachment, GLuint texture, GLint level) { + CALL_GL_API(glFramebufferTextureEXT, target, attachment, texture, level); +} +void API_ENTRY(glVertexAttribDivisorEXT)(GLuint index, GLuint divisor) { + CALL_GL_API(glVertexAttribDivisorEXT, index, divisor); +} +void * API_ENTRY(glMapBufferRangeEXT)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { + CALL_GL_API_RETURN(glMapBufferRangeEXT, target, offset, length, access); +} +void API_ENTRY(glFlushMappedBufferRangeEXT)(GLenum target, GLintptr offset, GLsizeiptr length) { + CALL_GL_API(glFlushMappedBufferRangeEXT, target, offset, length); +} +void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) { + CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount); +} +void API_ENTRY(glMultiDrawElementsEXT)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount) { + CALL_GL_API(glMultiDrawElementsEXT, mode, count, type, indices, primcount); +} +void API_ENTRY(glMultiDrawArraysIndirectEXT)(GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride) { + CALL_GL_API(glMultiDrawArraysIndirectEXT, mode, indirect, drawcount, stride); +} +void API_ENTRY(glMultiDrawElementsIndirectEXT)(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride) { + CALL_GL_API(glMultiDrawElementsIndirectEXT, mode, type, indirect, drawcount, stride); +} +void API_ENTRY(glRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { + CALL_GL_API(glRenderbufferStorageMultisampleEXT, target, samples, internalformat, width, height); +} +void API_ENTRY(glFramebufferTexture2DMultisampleEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) { + CALL_GL_API(glFramebufferTexture2DMultisampleEXT, target, attachment, textarget, texture, level, samples); +} +void API_ENTRY(glReadBufferIndexedEXT)(GLenum src, GLint index) { + CALL_GL_API(glReadBufferIndexedEXT, src, index); +} +void API_ENTRY(glDrawBuffersIndexedEXT)(GLint n, const GLenum *location, const GLint *indices) { + CALL_GL_API(glDrawBuffersIndexedEXT, n, location, indices); +} +void API_ENTRY(glGetIntegeri_vEXT)(GLenum target, GLuint index, GLint *data) { + CALL_GL_API(glGetIntegeri_vEXT, target, index, data); +} +void API_ENTRY(glPrimitiveBoundingBoxEXT)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) { + CALL_GL_API(glPrimitiveBoundingBoxEXT, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW); +} +void API_ENTRY(glRasterSamplesEXT)(GLuint samples, GLboolean fixedsamplelocations) { + CALL_GL_API(glRasterSamplesEXT, samples, fixedsamplelocations); +} +GLenum API_ENTRY(glGetGraphicsResetStatusEXT)(void) { + CALL_GL_API_RETURN(glGetGraphicsResetStatusEXT); +} +void API_ENTRY(glReadnPixelsEXT)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) { + CALL_GL_API(glReadnPixelsEXT, x, y, width, height, format, type, bufSize, data); +} +void API_ENTRY(glGetnUniformfvEXT)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params) { + CALL_GL_API(glGetnUniformfvEXT, program, location, bufSize, params); +} +void API_ENTRY(glGetnUniformivEXT)(GLuint program, GLint location, GLsizei bufSize, GLint *params) { + CALL_GL_API(glGetnUniformivEXT, program, location, bufSize, params); +} +void API_ENTRY(glActiveShaderProgramEXT)(GLuint pipeline, GLuint program) { + CALL_GL_API(glActiveShaderProgramEXT, pipeline, program); +} +void API_ENTRY(glBindProgramPipelineEXT)(GLuint pipeline) { + CALL_GL_API(glBindProgramPipelineEXT, pipeline); +} +GLuint API_ENTRY(glCreateShaderProgramvEXT)(GLenum type, GLsizei count, const GLchar **strings) { + CALL_GL_API_RETURN(glCreateShaderProgramvEXT, type, count, strings); +} +void API_ENTRY(glDeleteProgramPipelinesEXT)(GLsizei n, const GLuint *pipelines) { + CALL_GL_API(glDeleteProgramPipelinesEXT, n, pipelines); +} +void API_ENTRY(glGenProgramPipelinesEXT)(GLsizei n, GLuint *pipelines) { + CALL_GL_API(glGenProgramPipelinesEXT, n, pipelines); +} +void API_ENTRY(glGetProgramPipelineInfoLogEXT)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { + CALL_GL_API(glGetProgramPipelineInfoLogEXT, pipeline, bufSize, length, infoLog); +} +void API_ENTRY(glGetProgramPipelineivEXT)(GLuint pipeline, GLenum pname, GLint *params) { + CALL_GL_API(glGetProgramPipelineivEXT, pipeline, pname, params); +} +GLboolean API_ENTRY(glIsProgramPipelineEXT)(GLuint pipeline) { + CALL_GL_API_RETURN(glIsProgramPipelineEXT, pipeline); +} +void API_ENTRY(glProgramParameteriEXT)(GLuint program, GLenum pname, GLint value) { + CALL_GL_API(glProgramParameteriEXT, program, pname, value); +} +void API_ENTRY(glProgramUniform1fEXT)(GLuint program, GLint location, GLfloat v0) { + CALL_GL_API(glProgramUniform1fEXT, program, location, v0); +} +void API_ENTRY(glProgramUniform1fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glProgramUniform1fvEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform1iEXT)(GLuint program, GLint location, GLint v0) { + CALL_GL_API(glProgramUniform1iEXT, program, location, v0); +} +void API_ENTRY(glProgramUniform1ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glProgramUniform1ivEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform2fEXT)(GLuint program, GLint location, GLfloat v0, GLfloat v1) { + CALL_GL_API(glProgramUniform2fEXT, program, location, v0, v1); +} +void API_ENTRY(glProgramUniform2fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glProgramUniform2fvEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform2iEXT)(GLuint program, GLint location, GLint v0, GLint v1) { + CALL_GL_API(glProgramUniform2iEXT, program, location, v0, v1); +} +void API_ENTRY(glProgramUniform2ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glProgramUniform2ivEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform3fEXT)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { + CALL_GL_API(glProgramUniform3fEXT, program, location, v0, v1, v2); +} +void API_ENTRY(glProgramUniform3fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glProgramUniform3fvEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform3iEXT)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2) { + CALL_GL_API(glProgramUniform3iEXT, program, location, v0, v1, v2); +} +void API_ENTRY(glProgramUniform3ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glProgramUniform3ivEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform4fEXT)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { + CALL_GL_API(glProgramUniform4fEXT, program, location, v0, v1, v2, v3); +} +void API_ENTRY(glProgramUniform4fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) { + CALL_GL_API(glProgramUniform4fvEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform4iEXT)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) { + CALL_GL_API(glProgramUniform4iEXT, program, location, v0, v1, v2, v3); +} +void API_ENTRY(glProgramUniform4ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) { + CALL_GL_API(glProgramUniform4ivEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniformMatrix2fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix2fvEXT, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix3fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix3fvEXT, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix4fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix4fvEXT, program, location, count, transpose, value); +} +void API_ENTRY(glUseProgramStagesEXT)(GLuint pipeline, GLbitfield stages, GLuint program) { + CALL_GL_API(glUseProgramStagesEXT, pipeline, stages, program); +} +void API_ENTRY(glValidateProgramPipelineEXT)(GLuint pipeline) { + CALL_GL_API(glValidateProgramPipelineEXT, pipeline); +} +void API_ENTRY(glProgramUniform1uiEXT)(GLuint program, GLint location, GLuint v0) { + CALL_GL_API(glProgramUniform1uiEXT, program, location, v0); +} +void API_ENTRY(glProgramUniform2uiEXT)(GLuint program, GLint location, GLuint v0, GLuint v1) { + CALL_GL_API(glProgramUniform2uiEXT, program, location, v0, v1); +} +void API_ENTRY(glProgramUniform3uiEXT)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) { + CALL_GL_API(glProgramUniform3uiEXT, program, location, v0, v1, v2); +} +void API_ENTRY(glProgramUniform4uiEXT)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { + CALL_GL_API(glProgramUniform4uiEXT, program, location, v0, v1, v2, v3); +} +void API_ENTRY(glProgramUniform1uivEXT)(GLuint program, GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glProgramUniform1uivEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform2uivEXT)(GLuint program, GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glProgramUniform2uivEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform3uivEXT)(GLuint program, GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glProgramUniform3uivEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniform4uivEXT)(GLuint program, GLint location, GLsizei count, const GLuint *value) { + CALL_GL_API(glProgramUniform4uivEXT, program, location, count, value); +} +void API_ENTRY(glProgramUniformMatrix2x3fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix2x3fvEXT, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix3x2fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix3x2fvEXT, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix2x4fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix2x4fvEXT, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix4x2fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix4x2fvEXT, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix3x4fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix3x4fvEXT, program, location, count, transpose, value); +} +void API_ENTRY(glProgramUniformMatrix4x3fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { + CALL_GL_API(glProgramUniformMatrix4x3fvEXT, program, location, count, transpose, value); +} +void API_ENTRY(glTexPageCommitmentEXT)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit) { + CALL_GL_API(glTexPageCommitmentEXT, target, level, xoffset, yoffset, zoffset, width, height, depth, commit); +} +void API_ENTRY(glPatchParameteriEXT)(GLenum pname, GLint value) { + CALL_GL_API(glPatchParameteriEXT, pname, value); +} +void API_ENTRY(glTexParameterIivEXT)(GLenum target, GLenum pname, const GLint *params) { + CALL_GL_API(glTexParameterIivEXT, target, pname, params); +} +void API_ENTRY(glTexParameterIuivEXT)(GLenum target, GLenum pname, const GLuint *params) { + CALL_GL_API(glTexParameterIuivEXT, target, pname, params); +} +void API_ENTRY(glGetTexParameterIivEXT)(GLenum target, GLenum pname, GLint *params) { + CALL_GL_API(glGetTexParameterIivEXT, target, pname, params); +} +void API_ENTRY(glGetTexParameterIuivEXT)(GLenum target, GLenum pname, GLuint *params) { + CALL_GL_API(glGetTexParameterIuivEXT, target, pname, params); +} +void API_ENTRY(glSamplerParameterIivEXT)(GLuint sampler, GLenum pname, const GLint *param) { + CALL_GL_API(glSamplerParameterIivEXT, sampler, pname, param); +} +void API_ENTRY(glSamplerParameterIuivEXT)(GLuint sampler, GLenum pname, const GLuint *param) { + CALL_GL_API(glSamplerParameterIuivEXT, sampler, pname, param); +} +void API_ENTRY(glGetSamplerParameterIivEXT)(GLuint sampler, GLenum pname, GLint *params) { + CALL_GL_API(glGetSamplerParameterIivEXT, sampler, pname, params); +} +void API_ENTRY(glGetSamplerParameterIuivEXT)(GLuint sampler, GLenum pname, GLuint *params) { + CALL_GL_API(glGetSamplerParameterIuivEXT, sampler, pname, params); +} +void API_ENTRY(glTexBufferEXT)(GLenum target, GLenum internalformat, GLuint buffer) { + CALL_GL_API(glTexBufferEXT, target, internalformat, buffer); +} +void API_ENTRY(glTexBufferRangeEXT)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) { + CALL_GL_API(glTexBufferRangeEXT, target, internalformat, buffer, offset, size); +} +void API_ENTRY(glTexStorage1DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) { + CALL_GL_API(glTexStorage1DEXT, target, levels, internalformat, width); +} +void API_ENTRY(glTexStorage2DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { + CALL_GL_API(glTexStorage2DEXT, target, levels, internalformat, width, height); +} +void API_ENTRY(glTexStorage3DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { + CALL_GL_API(glTexStorage3DEXT, target, levels, internalformat, width, height, depth); +} +void API_ENTRY(glTextureStorage1DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) { + CALL_GL_API(glTextureStorage1DEXT, texture, target, levels, internalformat, width); +} +void API_ENTRY(glTextureStorage2DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { + CALL_GL_API(glTextureStorage2DEXT, texture, target, levels, internalformat, width, height); +} +void API_ENTRY(glTextureStorage3DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { + CALL_GL_API(glTextureStorage3DEXT, texture, target, levels, internalformat, width, height, depth); +} +void API_ENTRY(glTextureViewEXT)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) { + CALL_GL_API(glTextureViewEXT, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers); +}
\ No newline at end of file diff --git a/libs/hwui/debug/unwrap_gles.h b/libs/hwui/debug/gles_undefine.h index 7716a735a63b..e43829d98e38 100644 --- a/libs/hwui/debug/unwrap_gles.h +++ b/libs/hwui/debug/gles_undefine.h @@ -14,9 +14,6 @@ * limitations under the License. */ -#ifdef HWUI_GLES_WRAP_ENABLED -#undef HWUI_GLES_WRAP_ENABLED - #undef glActiveShaderProgram #undef glActiveShaderProgramEXT #undef glActiveTexture @@ -914,5 +911,3 @@ #undef glWaitSyncAPPLE #undef glWeightPathsNV #undef glWeightPointerOES - -#endif // HWUI_GLES_WRAP_ENABLED diff --git a/libs/hwui/debug/nullegl.cpp b/libs/hwui/debug/nullegl.cpp index b6cc2f247627..1ce180dd7543 100644 --- a/libs/hwui/debug/nullegl.cpp +++ b/libs/hwui/debug/nullegl.cpp @@ -68,6 +68,9 @@ EGLBoolean eglTerminate(EGLDisplay dpy) { } const char * eglQueryString(EGLDisplay dpy, EGLint name) { + if (name == EGL_EXTENSIONS) { + return "EGL_KHR_swap_buffers_with_damage"; + } return ""; } @@ -148,6 +151,10 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { return EGL_TRUE; } +EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint rectCount) { + return EGL_TRUE; +} + EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { return (EGLImageKHR) malloc(sizeof(EGLImageKHR)); } diff --git a/libs/hwui/debug/nullgles.cpp b/libs/hwui/debug/nullgles.cpp deleted file mode 100644 index 8689f9814f7b..000000000000 --- a/libs/hwui/debug/nullgles.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright(C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0(the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "unwrap_gles.h" - -#include <GLES3/gl3.h> -#include <GLES2/gl2ext.h> - -#include <stdlib.h> -#include <string.h> - -struct { - GLboolean scissorEnabled; -} gState; - -void glGenCommon(GLsizei n, GLuint *buffers) { - static GLuint nextId = 0; - int i; - for(i = 0; i < n; i++) { - buffers[i] = ++nextId; - } -} - -void glGenBuffers(GLsizei n, GLuint *buffers) { - glGenCommon(n, buffers); -} - -void glGenFramebuffers(GLsizei n, GLuint *framebuffers) { - glGenCommon(n, framebuffers); -} - -void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) { - glGenCommon(n, renderbuffers); -} - -void glGenTextures(GLsizei n, GLuint *textures) { - glGenCommon(n, textures); -} - -GLuint glCreateProgram(void) { - static GLuint nextProgram = 0; - return ++nextProgram; -} - -GLuint glCreateShader(GLenum type) { - static GLuint nextShader = 0; - return ++nextShader; -} - -void glGetProgramiv(GLuint program, GLenum pname, GLint *params) { - switch (pname) { - case GL_DELETE_STATUS: - case GL_LINK_STATUS: - case GL_VALIDATE_STATUS: - *params = GL_TRUE; - break; - case GL_INFO_LOG_LENGTH: - *params = 16; - break; - } -} - -void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { - *length = snprintf(infoLog, bufSize, "success"); - if (*length >= bufSize) { - *length = bufSize - 1; - } -} - -void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) { - switch (pname) { - case GL_COMPILE_STATUS: - case GL_DELETE_STATUS: - *params = GL_TRUE; - } -} - -void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { - *length = snprintf(infoLog, bufSize, "success"); - if (*length >= bufSize) { - *length = bufSize - 1; - } -} - -void setBooleanState(GLenum cap, GLboolean value) { - switch (cap) { - case GL_SCISSOR_TEST: - gState.scissorEnabled = value; - break; - } -} - -void glEnable(GLenum cap) { - setBooleanState(cap, GL_TRUE); -} - -void glDisable(GLenum cap) { - setBooleanState(cap, GL_FALSE); -} - -GLboolean glIsEnabled(GLenum cap) { - switch (cap) { - case GL_SCISSOR_TEST: - return gState.scissorEnabled; - default: - return GL_FALSE; - } -} - -void glGetIntegerv(GLenum pname, GLint *data) { - switch (pname) { - case GL_MAX_TEXTURE_SIZE: - *data = 2048; - break; - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: - *data = 4; - break; - default: - *data = 0; - } -} - -GLenum glCheckFramebufferStatus(GLenum target) { - switch (target) { - case GL_FRAMEBUFFER: - return GL_FRAMEBUFFER_COMPLETE; - default: - return 0; // error case - } -} - -const char* getString(GLenum name) { - switch (name) { - case GL_VENDOR: - return "android"; - case GL_RENDERER: - return "null"; - case GL_VERSION: - return "OpenGL ES 2.0 rev1"; - case GL_SHADING_LANGUAGE_VERSION: - return "OpenGL ES GLSL ES 2.0 rev1"; - case GL_EXTENSIONS: - default: - return ""; - } -} - -const GLubyte* glGetString(GLenum name) { - return (GLubyte*) getString(name); -} - -void glActiveTexture(GLenum texture) {} -void glAttachShader(GLuint program, GLuint shader) {} -void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) {} -void glBindBuffer(GLenum target, GLuint buffer) {} -void glBindFramebuffer(GLenum target, GLuint framebuffer) {} -void glBindRenderbuffer(GLenum target, GLuint renderbuffer) {} -void glBindTexture(GLenum target, GLuint texture) {} -void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {} -void glBlendEquation(GLenum mode) {} -void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {} -void glBlendFunc(GLenum sfactor, GLenum dfactor) {} -void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {} -void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {} -void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {} -void glClear(GLbitfield mask) {} -void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {} -void glClearDepthf(GLfloat d) {} -void glClearStencil(GLint s) {} -void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {} -void glCompileShader(GLuint shader) {} -void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) {} -void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {} -void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {} -void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {} -void glCullFace(GLenum mode) {} -void glDeleteBuffers(GLsizei n, const GLuint *buffers) {} -void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {} -void glDeleteProgram(GLuint program) {} -void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {} -void glDeleteShader(GLuint shader) {} -void glDeleteTextures(GLsizei n, const GLuint *textures) {} -void glDepthFunc(GLenum func) {} -void glDepthMask(GLboolean flag) {} -void glDepthRangef(GLfloat n, GLfloat f) {} -void glDetachShader(GLuint program, GLuint shader) {} -void glDisableVertexAttribArray(GLuint index) {} -void glDrawArrays(GLenum mode, GLint first, GLsizei count) {} -void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {} -void glEnableVertexAttribArray(GLuint index) {} -void glFinish(void) {} -void glFlush(void) {} -void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {} -void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {} -void glFrontFace(GLenum mode) {} -void glGenerateMipmap(GLenum target) {} -GLint glGetAttribLocation(GLuint program, const GLchar *name) { return 1; } -GLenum glGetError(void) { return GL_NO_ERROR; } -GLint glGetUniformLocation(GLuint program, const GLchar *name) { return 2; } -void glHint(GLenum target, GLenum mode) {} -void glLineWidth(GLfloat width) {} -void glLinkProgram(GLuint program) {} -void glPixelStorei(GLenum pname, GLint param) {} -void glPolygonOffset(GLfloat factor, GLfloat units) {} -void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) {} -void glReleaseShaderCompiler(void) {} -void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {} -void glSampleCoverage(GLfloat value, GLboolean invert) {} -void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {} -void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) {} -void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) {} -void glStencilFunc(GLenum func, GLint ref, GLuint mask) {} -void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {} -void glStencilMask(GLuint mask) {} -void glStencilMaskSeparate(GLenum face, GLuint mask) {} -void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {} -void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {} -void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {} -void glTexParameterf(GLenum target, GLenum pname, GLfloat param) {} -void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {} -void glTexParameteri(GLenum target, GLenum pname, GLint param) {} -void glTexParameteriv(GLenum target, GLenum pname, const GLint *params) {} -void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {} -void glUniform1f(GLint location, GLfloat v0) {} -void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) {} -void glUniform1i(GLint location, GLint v0) {} -void glUniform1iv(GLint location, GLsizei count, const GLint *value) {} -void glUniform2f(GLint location, GLfloat v0, GLfloat v1) {} -void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) {} -void glUniform2i(GLint location, GLint v0, GLint v1) {} -void glUniform2iv(GLint location, GLsizei count, const GLint *value) {} -void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {} -void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) {} -void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {} -void glUniform3iv(GLint location, GLsizei count, const GLint *value) {} -void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {} -void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) {} -void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {} -void glUniform4iv(GLint location, GLsizei count, const GLint *value) {} -void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {} -void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {} -void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {} -void glUseProgram(GLuint program) {} -void glValidateProgram(GLuint program) {} -void glVertexAttrib1f(GLuint index, GLfloat x) {} -void glVertexAttrib1fv(GLuint index, const GLfloat *v) {} -void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {} -void glVertexAttrib2fv(GLuint index, const GLfloat *v) {} -void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {} -void glVertexAttrib3fv(GLuint index, const GLfloat *v) {} -void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {} -void glVertexAttrib4fv(GLuint index, const GLfloat *v) {} -void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) {} -void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {} - - -// gles2 ext -void glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {} -void glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {} -void glPopGroupMarkerEXT(void) {} -void glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {} -void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) {} - -// GLES3 -void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { - return 0; -} - -GLboolean glUnmapBuffer(GLenum target) { - return GL_FALSE; -} diff --git a/libs/hwui/debug/wrap_gles.cpp b/libs/hwui/debug/wrap_gles.cpp index c4f2e3537fe8..8dc946e5667b 100644 --- a/libs/hwui/debug/wrap_gles.cpp +++ b/libs/hwui/debug/wrap_gles.cpp @@ -14,80 +14,20 @@ * limitations under the License. */ -#include "unwrap_gles.h" +#include "GlesDriver.h" -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES/gl.h> -#include <GLES/glext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <GLES3/gl3.h> -#include <GLES3/gl31.h> -#include <GLES3/gl32.h> +using namespace android::uirenderer::debug; -#include <cutils/log.h> +#undef API_ENTRY +#undef CALL_GL_API +#undef CALL_GL_API_RETURN -void assertNoGlErrors(const char* apicall) { - GLenum status = GL_NO_ERROR; - GLenum lastError = GL_NO_ERROR; - const char* lastErrorName = nullptr; - while ((status = glGetError()) != GL_NO_ERROR) { - lastError = status; - switch (status) { - case GL_INVALID_ENUM: - ALOGE("GL error: GL_INVALID_ENUM"); - lastErrorName = "GL_INVALID_ENUM"; - break; - case GL_INVALID_VALUE: - ALOGE("GL error: GL_INVALID_VALUE"); - lastErrorName = "GL_INVALID_VALUE"; - break; - case GL_INVALID_OPERATION: - ALOGE("GL error: GL_INVALID_OPERATION"); - lastErrorName = "GL_INVALID_OPERATION"; - break; - case GL_OUT_OF_MEMORY: - ALOGE("GL error: Out of memory!"); - lastErrorName = "GL_OUT_OF_MEMORY"; - break; - default: - ALOGE("GL error: 0x%x", status); - lastErrorName = "UNKNOWN"; - } - } - LOG_ALWAYS_FATAL_IF(lastError != GL_NO_ERROR, - "%s error! %s (0x%x)", apicall, lastErrorName, lastError); -} +#define API_ENTRY(x) x +#define CALL_GL_API(api, ...) GlesDriver::get()->api##_(__VA_ARGS__) +#define CALL_GL_API_RETURN(api, ...) return GlesDriver::get()->api##_(__VA_ARGS__) -#define API_ENTRY(x) wrap_##x -#define CALL_GL_API(x, ...) x(__VA_ARGS__); assertNoGlErrors(#x) -#define CALL_GL_API_RETURN(x, ...) auto ret = x(__VA_ARGS__);\ - assertNoGlErrors(#x);\ - return ret +#include "gles_stubs.in" -extern "C" { -#include <gl2_api.in> -#include <gl2ext_api.in> - -// libGLESv2 handles these specially, so they are not in gl2_api.in - -void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean *data) { - CALL_GL_API(glGetBooleanv, pname, data); -} -void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat *data) { - CALL_GL_API(glGetFloatv, pname, data); -} -void API_ENTRY(glGetIntegerv)(GLenum pname, GLint *data) { - CALL_GL_API(glGetIntegerv, pname, data); -} -const GLubyte * API_ENTRY(glGetString)(GLenum name) { - CALL_GL_API_RETURN(glGetString, name); -} -const GLubyte * API_ENTRY(glGetStringi)(GLenum name, GLuint index) { - CALL_GL_API_RETURN(glGetStringi, name, index); -} -void API_ENTRY(glGetInteger64v)(GLenum pname, GLint64 *data) { - CALL_GL_API(glGetInteger64v, pname, data); -} -} +#undef API_ENTRY +#undef CALL_GL_API +#undef CALL_GL_API_RETURN diff --git a/libs/hwui/debug/wrap_gles.h b/libs/hwui/debug/wrap_gles.h index 4a3537442e73..ecd46e249969 100644 --- a/libs/hwui/debug/wrap_gles.h +++ b/libs/hwui/debug/wrap_gles.h @@ -14,905 +14,15 @@ * limitations under the License. */ -#ifndef HWUI_GLES_WRAP_ENABLED +// #include'ing this file is bad, bad things should be compile errors +#ifdef HWUI_GLES_WRAP_ENABLED +#error wrap_gles.h should only be used as an auto-included header, don't directly #include it +#endif #define HWUI_GLES_WRAP_ENABLED -#define glActiveShaderProgram wrap_glActiveShaderProgram -#define glActiveShaderProgramEXT wrap_glActiveShaderProgramEXT -#define glActiveTexture wrap_glActiveTexture -#define glAlphaFunc wrap_glAlphaFunc -#define glAlphaFuncQCOM wrap_glAlphaFuncQCOM -#define glAlphaFuncx wrap_glAlphaFuncx -#define glAlphaFuncxOES wrap_glAlphaFuncxOES -#define glApplyFramebufferAttachmentCMAAINTEL wrap_glApplyFramebufferAttachmentCMAAINTEL -#define glAttachShader wrap_glAttachShader -#define glBeginConditionalRenderNV wrap_glBeginConditionalRenderNV -#define glBeginPerfMonitorAMD wrap_glBeginPerfMonitorAMD -#define glBeginPerfQueryINTEL wrap_glBeginPerfQueryINTEL -#define glBeginQuery wrap_glBeginQuery -#define glBeginQueryEXT wrap_glBeginQueryEXT -#define glBeginTransformFeedback wrap_glBeginTransformFeedback -#define glBindAttribLocation wrap_glBindAttribLocation -#define glBindBuffer wrap_glBindBuffer -#define glBindBufferBase wrap_glBindBufferBase -#define glBindBufferRange wrap_glBindBufferRange -#define glBindFragDataLocationEXT wrap_glBindFragDataLocationEXT -#define glBindFragDataLocationIndexedEXT wrap_glBindFragDataLocationIndexedEXT -#define glBindFramebuffer wrap_glBindFramebuffer -#define glBindFramebufferOES wrap_glBindFramebufferOES -#define glBindImageTexture wrap_glBindImageTexture -#define glBindProgramPipeline wrap_glBindProgramPipeline -#define glBindProgramPipelineEXT wrap_glBindProgramPipelineEXT -#define glBindRenderbuffer wrap_glBindRenderbuffer -#define glBindRenderbufferOES wrap_glBindRenderbufferOES -#define glBindSampler wrap_glBindSampler -#define glBindTexture wrap_glBindTexture -#define glBindTransformFeedback wrap_glBindTransformFeedback -#define glBindVertexArray wrap_glBindVertexArray -#define glBindVertexArrayOES wrap_glBindVertexArrayOES -#define glBindVertexBuffer wrap_glBindVertexBuffer -#define glBlendBarrier wrap_glBlendBarrier -#define glBlendBarrierKHR wrap_glBlendBarrierKHR -#define glBlendBarrierNV wrap_glBlendBarrierNV -#define glBlendColor wrap_glBlendColor -#define glBlendEquation wrap_glBlendEquation -#define glBlendEquationOES wrap_glBlendEquationOES -#define glBlendEquationSeparate wrap_glBlendEquationSeparate -#define glBlendEquationSeparateOES wrap_glBlendEquationSeparateOES -#define glBlendEquationSeparatei wrap_glBlendEquationSeparatei -#define glBlendEquationSeparateiEXT wrap_glBlendEquationSeparateiEXT -#define glBlendEquationSeparateiOES wrap_glBlendEquationSeparateiOES -#define glBlendEquationi wrap_glBlendEquationi -#define glBlendEquationiEXT wrap_glBlendEquationiEXT -#define glBlendEquationiOES wrap_glBlendEquationiOES -#define glBlendFunc wrap_glBlendFunc -#define glBlendFuncSeparate wrap_glBlendFuncSeparate -#define glBlendFuncSeparateOES wrap_glBlendFuncSeparateOES -#define glBlendFuncSeparatei wrap_glBlendFuncSeparatei -#define glBlendFuncSeparateiEXT wrap_glBlendFuncSeparateiEXT -#define glBlendFuncSeparateiOES wrap_glBlendFuncSeparateiOES -#define glBlendFunci wrap_glBlendFunci -#define glBlendFunciEXT wrap_glBlendFunciEXT -#define glBlendFunciOES wrap_glBlendFunciOES -#define glBlendParameteriNV wrap_glBlendParameteriNV -#define glBlitFramebuffer wrap_glBlitFramebuffer -#define glBlitFramebufferANGLE wrap_glBlitFramebufferANGLE -#define glBlitFramebufferNV wrap_glBlitFramebufferNV -#define glBufferData wrap_glBufferData -#define glBufferStorageEXT wrap_glBufferStorageEXT -#define glBufferSubData wrap_glBufferSubData -#define glCheckFramebufferStatus wrap_glCheckFramebufferStatus -#define glCheckFramebufferStatusOES wrap_glCheckFramebufferStatusOES -#define glClear wrap_glClear -#define glClearBufferfi wrap_glClearBufferfi -#define glClearBufferfv wrap_glClearBufferfv -#define glClearBufferiv wrap_glClearBufferiv -#define glClearBufferuiv wrap_glClearBufferuiv -#define glClearColor wrap_glClearColor -#define glClearColorx wrap_glClearColorx -#define glClearColorxOES wrap_glClearColorxOES -#define glClearDepthf wrap_glClearDepthf -#define glClearDepthfOES wrap_glClearDepthfOES -#define glClearDepthx wrap_glClearDepthx -#define glClearDepthxOES wrap_glClearDepthxOES -#define glClearStencil wrap_glClearStencil -#define glClientActiveTexture wrap_glClientActiveTexture -#define glClientWaitSync wrap_glClientWaitSync -#define glClientWaitSyncAPPLE wrap_glClientWaitSyncAPPLE -#define glClipPlanef wrap_glClipPlanef -#define glClipPlanefIMG wrap_glClipPlanefIMG -#define glClipPlanefOES wrap_glClipPlanefOES -#define glClipPlanex wrap_glClipPlanex -#define glClipPlanexIMG wrap_glClipPlanexIMG -#define glClipPlanexOES wrap_glClipPlanexOES -#define glColor4f wrap_glColor4f -#define glColor4ub wrap_glColor4ub -#define glColor4x wrap_glColor4x -#define glColor4xOES wrap_glColor4xOES -#define glColorMask wrap_glColorMask -#define glColorMaski wrap_glColorMaski -#define glColorMaskiEXT wrap_glColorMaskiEXT -#define glColorMaskiOES wrap_glColorMaskiOES -#define glColorPointer wrap_glColorPointer -#define glCompileShader wrap_glCompileShader -#define glCompressedTexImage2D wrap_glCompressedTexImage2D -#define glCompressedTexImage3D wrap_glCompressedTexImage3D -#define glCompressedTexImage3DOES wrap_glCompressedTexImage3DOES -#define glCompressedTexSubImage2D wrap_glCompressedTexSubImage2D -#define glCompressedTexSubImage3D wrap_glCompressedTexSubImage3D -#define glCompressedTexSubImage3DOES wrap_glCompressedTexSubImage3DOES -#define glCopyBufferSubData wrap_glCopyBufferSubData -#define glCopyBufferSubDataNV wrap_glCopyBufferSubDataNV -#define glCopyImageSubData wrap_glCopyImageSubData -#define glCopyImageSubDataEXT wrap_glCopyImageSubDataEXT -#define glCopyImageSubDataOES wrap_glCopyImageSubDataOES -#define glCopyPathNV wrap_glCopyPathNV -#define glCopyTexImage2D wrap_glCopyTexImage2D -#define glCopyTexSubImage2D wrap_glCopyTexSubImage2D -#define glCopyTexSubImage3D wrap_glCopyTexSubImage3D -#define glCopyTexSubImage3DOES wrap_glCopyTexSubImage3DOES -#define glCopyTextureLevelsAPPLE wrap_glCopyTextureLevelsAPPLE -#define glCoverFillPathInstancedNV wrap_glCoverFillPathInstancedNV -#define glCoverFillPathNV wrap_glCoverFillPathNV -#define glCoverStrokePathInstancedNV wrap_glCoverStrokePathInstancedNV -#define glCoverStrokePathNV wrap_glCoverStrokePathNV -#define glCoverageMaskNV wrap_glCoverageMaskNV -#define glCoverageModulationNV wrap_glCoverageModulationNV -#define glCoverageModulationTableNV wrap_glCoverageModulationTableNV -#define glCoverageOperationNV wrap_glCoverageOperationNV -#define glCreatePerfQueryINTEL wrap_glCreatePerfQueryINTEL -#define glCreateProgram wrap_glCreateProgram -#define glCreateShader wrap_glCreateShader -#define glCreateShaderProgramv wrap_glCreateShaderProgramv -#define glCreateShaderProgramvEXT wrap_glCreateShaderProgramvEXT -#define glCullFace wrap_glCullFace -#define glCurrentPaletteMatrixOES wrap_glCurrentPaletteMatrixOES -#define glDebugMessageCallback wrap_glDebugMessageCallback -#define glDebugMessageCallbackKHR wrap_glDebugMessageCallbackKHR -#define glDebugMessageControl wrap_glDebugMessageControl -#define glDebugMessageControlKHR wrap_glDebugMessageControlKHR -#define glDebugMessageInsert wrap_glDebugMessageInsert -#define glDebugMessageInsertKHR wrap_glDebugMessageInsertKHR -#define glDeleteBuffers wrap_glDeleteBuffers -#define glDeleteFencesNV wrap_glDeleteFencesNV -#define glDeleteFramebuffers wrap_glDeleteFramebuffers -#define glDeleteFramebuffersOES wrap_glDeleteFramebuffersOES -#define glDeletePathsNV wrap_glDeletePathsNV -#define glDeletePerfMonitorsAMD wrap_glDeletePerfMonitorsAMD -#define glDeletePerfQueryINTEL wrap_glDeletePerfQueryINTEL -#define glDeleteProgram wrap_glDeleteProgram -#define glDeleteProgramPipelines wrap_glDeleteProgramPipelines -#define glDeleteProgramPipelinesEXT wrap_glDeleteProgramPipelinesEXT -#define glDeleteQueries wrap_glDeleteQueries -#define glDeleteQueriesEXT wrap_glDeleteQueriesEXT -#define glDeleteRenderbuffers wrap_glDeleteRenderbuffers -#define glDeleteRenderbuffersOES wrap_glDeleteRenderbuffersOES -#define glDeleteSamplers wrap_glDeleteSamplers -#define glDeleteShader wrap_glDeleteShader -#define glDeleteSync wrap_glDeleteSync -#define glDeleteSyncAPPLE wrap_glDeleteSyncAPPLE -#define glDeleteTextures wrap_glDeleteTextures -#define glDeleteTransformFeedbacks wrap_glDeleteTransformFeedbacks -#define glDeleteVertexArrays wrap_glDeleteVertexArrays -#define glDeleteVertexArraysOES wrap_glDeleteVertexArraysOES -#define glDepthFunc wrap_glDepthFunc -#define glDepthMask wrap_glDepthMask -#define glDepthRangeArrayfvNV wrap_glDepthRangeArrayfvNV -#define glDepthRangeIndexedfNV wrap_glDepthRangeIndexedfNV -#define glDepthRangef wrap_glDepthRangef -#define glDepthRangefOES wrap_glDepthRangefOES -#define glDepthRangex wrap_glDepthRangex -#define glDepthRangexOES wrap_glDepthRangexOES -#define glDetachShader wrap_glDetachShader -#define glDisable wrap_glDisable -#define glDisableClientState wrap_glDisableClientState -#define glDisableDriverControlQCOM wrap_glDisableDriverControlQCOM -#define glDisableVertexAttribArray wrap_glDisableVertexAttribArray -#define glDisablei wrap_glDisablei -#define glDisableiEXT wrap_glDisableiEXT -#define glDisableiNV wrap_glDisableiNV -#define glDisableiOES wrap_glDisableiOES -#define glDiscardFramebufferEXT wrap_glDiscardFramebufferEXT -#define glDispatchCompute wrap_glDispatchCompute -#define glDispatchComputeIndirect wrap_glDispatchComputeIndirect -#define glDrawArrays wrap_glDrawArrays -#define glDrawArraysIndirect wrap_glDrawArraysIndirect -#define glDrawArraysInstanced wrap_glDrawArraysInstanced -#define glDrawArraysInstancedANGLE wrap_glDrawArraysInstancedANGLE -#define glDrawArraysInstancedBaseInstanceEXT wrap_glDrawArraysInstancedBaseInstanceEXT -#define glDrawArraysInstancedEXT wrap_glDrawArraysInstancedEXT -#define glDrawArraysInstancedNV wrap_glDrawArraysInstancedNV -#define glDrawBuffers wrap_glDrawBuffers -#define glDrawBuffersEXT wrap_glDrawBuffersEXT -#define glDrawBuffersIndexedEXT wrap_glDrawBuffersIndexedEXT -#define glDrawBuffersNV wrap_glDrawBuffersNV -#define glDrawElements wrap_glDrawElements -#define glDrawElementsBaseVertex wrap_glDrawElementsBaseVertex -#define glDrawElementsBaseVertexEXT wrap_glDrawElementsBaseVertexEXT -#define glDrawElementsBaseVertexOES wrap_glDrawElementsBaseVertexOES -#define glDrawElementsIndirect wrap_glDrawElementsIndirect -#define glDrawElementsInstanced wrap_glDrawElementsInstanced -#define glDrawElementsInstancedANGLE wrap_glDrawElementsInstancedANGLE -#define glDrawElementsInstancedBaseInstanceEXT wrap_glDrawElementsInstancedBaseInstanceEXT -#define glDrawElementsInstancedBaseVertex wrap_glDrawElementsInstancedBaseVertex -#define glDrawElementsInstancedBaseVertexBaseInstanceEXT wrap_glDrawElementsInstancedBaseVertexBaseInstanceEXT -#define glDrawElementsInstancedBaseVertexEXT wrap_glDrawElementsInstancedBaseVertexEXT -#define glDrawElementsInstancedBaseVertexOES wrap_glDrawElementsInstancedBaseVertexOES -#define glDrawElementsInstancedEXT wrap_glDrawElementsInstancedEXT -#define glDrawElementsInstancedNV wrap_glDrawElementsInstancedNV -#define glDrawRangeElements wrap_glDrawRangeElements -#define glDrawRangeElementsBaseVertex wrap_glDrawRangeElementsBaseVertex -#define glDrawRangeElementsBaseVertexEXT wrap_glDrawRangeElementsBaseVertexEXT -#define glDrawRangeElementsBaseVertexOES wrap_glDrawRangeElementsBaseVertexOES -#define glDrawTexfOES wrap_glDrawTexfOES -#define glDrawTexfvOES wrap_glDrawTexfvOES -#define glDrawTexiOES wrap_glDrawTexiOES -#define glDrawTexivOES wrap_glDrawTexivOES -#define glDrawTexsOES wrap_glDrawTexsOES -#define glDrawTexsvOES wrap_glDrawTexsvOES -#define glDrawTexxOES wrap_glDrawTexxOES -#define glDrawTexxvOES wrap_glDrawTexxvOES -#define glEGLImageTargetRenderbufferStorageOES wrap_glEGLImageTargetRenderbufferStorageOES -#define glEGLImageTargetTexture2DOES wrap_glEGLImageTargetTexture2DOES -#define glEnable wrap_glEnable -#define glEnableClientState wrap_glEnableClientState -#define glEnableDriverControlQCOM wrap_glEnableDriverControlQCOM -#define glEnableVertexAttribArray wrap_glEnableVertexAttribArray -#define glEnablei wrap_glEnablei -#define glEnableiEXT wrap_glEnableiEXT -#define glEnableiNV wrap_glEnableiNV -#define glEnableiOES wrap_glEnableiOES -#define glEndConditionalRenderNV wrap_glEndConditionalRenderNV -#define glEndPerfMonitorAMD wrap_glEndPerfMonitorAMD -#define glEndPerfQueryINTEL wrap_glEndPerfQueryINTEL -#define glEndQuery wrap_glEndQuery -#define glEndQueryEXT wrap_glEndQueryEXT -#define glEndTilingQCOM wrap_glEndTilingQCOM -#define glEndTransformFeedback wrap_glEndTransformFeedback -#define glExtGetBufferPointervQCOM wrap_glExtGetBufferPointervQCOM -#define glExtGetBuffersQCOM wrap_glExtGetBuffersQCOM -#define glExtGetFramebuffersQCOM wrap_glExtGetFramebuffersQCOM -#define glExtGetProgramBinarySourceQCOM wrap_glExtGetProgramBinarySourceQCOM -#define glExtGetProgramsQCOM wrap_glExtGetProgramsQCOM -#define glExtGetRenderbuffersQCOM wrap_glExtGetRenderbuffersQCOM -#define glExtGetShadersQCOM wrap_glExtGetShadersQCOM -#define glExtGetTexLevelParameterivQCOM wrap_glExtGetTexLevelParameterivQCOM -#define glExtGetTexSubImageQCOM wrap_glExtGetTexSubImageQCOM -#define glExtGetTexturesQCOM wrap_glExtGetTexturesQCOM -#define glExtIsProgramBinaryQCOM wrap_glExtIsProgramBinaryQCOM -#define glExtTexObjectStateOverrideiQCOM wrap_glExtTexObjectStateOverrideiQCOM -#define glFenceSync wrap_glFenceSync -#define glFenceSyncAPPLE wrap_glFenceSyncAPPLE -#define glFinish wrap_glFinish -#define glFinishFenceNV wrap_glFinishFenceNV -#define glFlush wrap_glFlush -#define glFlushMappedBufferRange wrap_glFlushMappedBufferRange -#define glFlushMappedBufferRangeEXT wrap_glFlushMappedBufferRangeEXT -#define glFogf wrap_glFogf -#define glFogfv wrap_glFogfv -#define glFogx wrap_glFogx -#define glFogxOES wrap_glFogxOES -#define glFogxv wrap_glFogxv -#define glFogxvOES wrap_glFogxvOES -#define glFragmentCoverageColorNV wrap_glFragmentCoverageColorNV -#define glFramebufferParameteri wrap_glFramebufferParameteri -#define glFramebufferRenderbuffer wrap_glFramebufferRenderbuffer -#define glFramebufferRenderbufferOES wrap_glFramebufferRenderbufferOES -#define glFramebufferSampleLocationsfvNV wrap_glFramebufferSampleLocationsfvNV -#define glFramebufferTexture wrap_glFramebufferTexture -#define glFramebufferTexture2D wrap_glFramebufferTexture2D -#define glFramebufferTexture2DMultisampleEXT wrap_glFramebufferTexture2DMultisampleEXT -#define glFramebufferTexture2DMultisampleIMG wrap_glFramebufferTexture2DMultisampleIMG -#define glFramebufferTexture2DOES wrap_glFramebufferTexture2DOES -#define glFramebufferTexture3DOES wrap_glFramebufferTexture3DOES -#define glFramebufferTextureEXT wrap_glFramebufferTextureEXT -#define glFramebufferTextureLayer wrap_glFramebufferTextureLayer -#define glFramebufferTextureMultisampleMultiviewOVR wrap_glFramebufferTextureMultisampleMultiviewOVR -#define glFramebufferTextureMultiviewOVR wrap_glFramebufferTextureMultiviewOVR -#define glFramebufferTextureOES wrap_glFramebufferTextureOES -#define glFrontFace wrap_glFrontFace -#define glFrustumf wrap_glFrustumf -#define glFrustumfOES wrap_glFrustumfOES -#define glFrustumx wrap_glFrustumx -#define glFrustumxOES wrap_glFrustumxOES -#define glGenBuffers wrap_glGenBuffers -#define glGenFencesNV wrap_glGenFencesNV -#define glGenFramebuffers wrap_glGenFramebuffers -#define glGenFramebuffersOES wrap_glGenFramebuffersOES -#define glGenPathsNV wrap_glGenPathsNV -#define glGenPerfMonitorsAMD wrap_glGenPerfMonitorsAMD -#define glGenProgramPipelines wrap_glGenProgramPipelines -#define glGenProgramPipelinesEXT wrap_glGenProgramPipelinesEXT -#define glGenQueries wrap_glGenQueries -#define glGenQueriesEXT wrap_glGenQueriesEXT -#define glGenRenderbuffers wrap_glGenRenderbuffers -#define glGenRenderbuffersOES wrap_glGenRenderbuffersOES -#define glGenSamplers wrap_glGenSamplers -#define glGenTextures wrap_glGenTextures -#define glGenTransformFeedbacks wrap_glGenTransformFeedbacks -#define glGenVertexArrays wrap_glGenVertexArrays -#define glGenVertexArraysOES wrap_glGenVertexArraysOES -#define glGenerateMipmap wrap_glGenerateMipmap -#define glGenerateMipmapOES wrap_glGenerateMipmapOES -#define glGetActiveAttrib wrap_glGetActiveAttrib -#define glGetActiveUniform wrap_glGetActiveUniform -#define glGetActiveUniformBlockName wrap_glGetActiveUniformBlockName -#define glGetActiveUniformBlockiv wrap_glGetActiveUniformBlockiv -#define glGetActiveUniformsiv wrap_glGetActiveUniformsiv -#define glGetAttachedShaders wrap_glGetAttachedShaders -#define glGetAttribLocation wrap_glGetAttribLocation -#define glGetBooleani_v wrap_glGetBooleani_v -#define glGetBooleanv wrap_glGetBooleanv -#define glGetBufferParameteri64v wrap_glGetBufferParameteri64v -#define glGetBufferParameteriv wrap_glGetBufferParameteriv -#define glGetBufferPointerv wrap_glGetBufferPointerv -#define glGetBufferPointervOES wrap_glGetBufferPointervOES -#define glGetClipPlanef wrap_glGetClipPlanef -#define glGetClipPlanefOES wrap_glGetClipPlanefOES -#define glGetClipPlanex wrap_glGetClipPlanex -#define glGetClipPlanexOES wrap_glGetClipPlanexOES -#define glGetCoverageModulationTableNV wrap_glGetCoverageModulationTableNV -#define glGetDebugMessageLog wrap_glGetDebugMessageLog -#define glGetDebugMessageLogKHR wrap_glGetDebugMessageLogKHR -#define glGetDriverControlStringQCOM wrap_glGetDriverControlStringQCOM -#define glGetDriverControlsQCOM wrap_glGetDriverControlsQCOM -#define glGetError wrap_glGetError -#define glGetFenceivNV wrap_glGetFenceivNV -#define glGetFirstPerfQueryIdINTEL wrap_glGetFirstPerfQueryIdINTEL -#define glGetFixedv wrap_glGetFixedv -#define glGetFixedvOES wrap_glGetFixedvOES -#define glGetFloati_vNV wrap_glGetFloati_vNV -#define glGetFloatv wrap_glGetFloatv -#define glGetFragDataIndexEXT wrap_glGetFragDataIndexEXT -#define glGetFragDataLocation wrap_glGetFragDataLocation -#define glGetFramebufferAttachmentParameteriv wrap_glGetFramebufferAttachmentParameteriv -#define glGetFramebufferAttachmentParameterivOES wrap_glGetFramebufferAttachmentParameterivOES -#define glGetFramebufferParameteriv wrap_glGetFramebufferParameteriv -#define glGetGraphicsResetStatus wrap_glGetGraphicsResetStatus -#define glGetGraphicsResetStatusEXT wrap_glGetGraphicsResetStatusEXT -#define glGetGraphicsResetStatusKHR wrap_glGetGraphicsResetStatusKHR -#define glGetImageHandleNV wrap_glGetImageHandleNV -#define glGetInteger64i_v wrap_glGetInteger64i_v -#define glGetInteger64v wrap_glGetInteger64v -#define glGetInteger64vAPPLE wrap_glGetInteger64vAPPLE -#define glGetIntegeri_v wrap_glGetIntegeri_v -#define glGetIntegeri_vEXT wrap_glGetIntegeri_vEXT -#define glGetIntegerv wrap_glGetIntegerv -#define glGetInternalformatSampleivNV wrap_glGetInternalformatSampleivNV -#define glGetInternalformativ wrap_glGetInternalformativ -#define glGetLightfv wrap_glGetLightfv -#define glGetLightxv wrap_glGetLightxv -#define glGetLightxvOES wrap_glGetLightxvOES -#define glGetMaterialfv wrap_glGetMaterialfv -#define glGetMaterialxv wrap_glGetMaterialxv -#define glGetMaterialxvOES wrap_glGetMaterialxvOES -#define glGetMultisamplefv wrap_glGetMultisamplefv -#define glGetNextPerfQueryIdINTEL wrap_glGetNextPerfQueryIdINTEL -#define glGetObjectLabel wrap_glGetObjectLabel -#define glGetObjectLabelEXT wrap_glGetObjectLabelEXT -#define glGetObjectLabelKHR wrap_glGetObjectLabelKHR -#define glGetObjectPtrLabel wrap_glGetObjectPtrLabel -#define glGetObjectPtrLabelKHR wrap_glGetObjectPtrLabelKHR -#define glGetPathCommandsNV wrap_glGetPathCommandsNV -#define glGetPathCoordsNV wrap_glGetPathCoordsNV -#define glGetPathDashArrayNV wrap_glGetPathDashArrayNV -#define glGetPathLengthNV wrap_glGetPathLengthNV -#define glGetPathMetricRangeNV wrap_glGetPathMetricRangeNV -#define glGetPathMetricsNV wrap_glGetPathMetricsNV -#define glGetPathParameterfvNV wrap_glGetPathParameterfvNV -#define glGetPathParameterivNV wrap_glGetPathParameterivNV -#define glGetPathSpacingNV wrap_glGetPathSpacingNV -#define glGetPerfCounterInfoINTEL wrap_glGetPerfCounterInfoINTEL -#define glGetPerfMonitorCounterDataAMD wrap_glGetPerfMonitorCounterDataAMD -#define glGetPerfMonitorCounterInfoAMD wrap_glGetPerfMonitorCounterInfoAMD -#define glGetPerfMonitorCounterStringAMD wrap_glGetPerfMonitorCounterStringAMD -#define glGetPerfMonitorCountersAMD wrap_glGetPerfMonitorCountersAMD -#define glGetPerfMonitorGroupStringAMD wrap_glGetPerfMonitorGroupStringAMD -#define glGetPerfMonitorGroupsAMD wrap_glGetPerfMonitorGroupsAMD -#define glGetPerfQueryDataINTEL wrap_glGetPerfQueryDataINTEL -#define glGetPerfQueryIdByNameINTEL wrap_glGetPerfQueryIdByNameINTEL -#define glGetPerfQueryInfoINTEL wrap_glGetPerfQueryInfoINTEL -#define glGetPointerv wrap_glGetPointerv -#define glGetPointervKHR wrap_glGetPointervKHR -#define glGetProgramBinary wrap_glGetProgramBinary -#define glGetProgramBinaryOES wrap_glGetProgramBinaryOES -#define glGetProgramInfoLog wrap_glGetProgramInfoLog -#define glGetProgramInterfaceiv wrap_glGetProgramInterfaceiv -#define glGetProgramPipelineInfoLog wrap_glGetProgramPipelineInfoLog -#define glGetProgramPipelineInfoLogEXT wrap_glGetProgramPipelineInfoLogEXT -#define glGetProgramPipelineiv wrap_glGetProgramPipelineiv -#define glGetProgramPipelineivEXT wrap_glGetProgramPipelineivEXT -#define glGetProgramResourceIndex wrap_glGetProgramResourceIndex -#define glGetProgramResourceLocation wrap_glGetProgramResourceLocation -#define glGetProgramResourceLocationIndexEXT wrap_glGetProgramResourceLocationIndexEXT -#define glGetProgramResourceName wrap_glGetProgramResourceName -#define glGetProgramResourcefvNV wrap_glGetProgramResourcefvNV -#define glGetProgramResourceiv wrap_glGetProgramResourceiv -#define glGetProgramiv wrap_glGetProgramiv -#define glGetQueryObjecti64vEXT wrap_glGetQueryObjecti64vEXT -#define glGetQueryObjectivEXT wrap_glGetQueryObjectivEXT -#define glGetQueryObjectui64vEXT wrap_glGetQueryObjectui64vEXT -#define glGetQueryObjectuiv wrap_glGetQueryObjectuiv -#define glGetQueryObjectuivEXT wrap_glGetQueryObjectuivEXT -#define glGetQueryiv wrap_glGetQueryiv -#define glGetQueryivEXT wrap_glGetQueryivEXT -#define glGetRenderbufferParameteriv wrap_glGetRenderbufferParameteriv -#define glGetRenderbufferParameterivOES wrap_glGetRenderbufferParameterivOES -#define glGetSamplerParameterIiv wrap_glGetSamplerParameterIiv -#define glGetSamplerParameterIivEXT wrap_glGetSamplerParameterIivEXT -#define glGetSamplerParameterIivOES wrap_glGetSamplerParameterIivOES -#define glGetSamplerParameterIuiv wrap_glGetSamplerParameterIuiv -#define glGetSamplerParameterIuivEXT wrap_glGetSamplerParameterIuivEXT -#define glGetSamplerParameterIuivOES wrap_glGetSamplerParameterIuivOES -#define glGetSamplerParameterfv wrap_glGetSamplerParameterfv -#define glGetSamplerParameteriv wrap_glGetSamplerParameteriv -#define glGetShaderInfoLog wrap_glGetShaderInfoLog -#define glGetShaderPrecisionFormat wrap_glGetShaderPrecisionFormat -#define glGetShaderSource wrap_glGetShaderSource -#define glGetShaderiv wrap_glGetShaderiv -#define glGetString wrap_glGetString -#define glGetStringi wrap_glGetStringi -#define glGetSynciv wrap_glGetSynciv -#define glGetSyncivAPPLE wrap_glGetSyncivAPPLE -#define glGetTexEnvfv wrap_glGetTexEnvfv -#define glGetTexEnviv wrap_glGetTexEnviv -#define glGetTexEnvxv wrap_glGetTexEnvxv -#define glGetTexEnvxvOES wrap_glGetTexEnvxvOES -#define glGetTexGenfvOES wrap_glGetTexGenfvOES -#define glGetTexGenivOES wrap_glGetTexGenivOES -#define glGetTexGenxvOES wrap_glGetTexGenxvOES -#define glGetTexLevelParameterfv wrap_glGetTexLevelParameterfv -#define glGetTexLevelParameteriv wrap_glGetTexLevelParameteriv -#define glGetTexParameterIiv wrap_glGetTexParameterIiv -#define glGetTexParameterIivEXT wrap_glGetTexParameterIivEXT -#define glGetTexParameterIivOES wrap_glGetTexParameterIivOES -#define glGetTexParameterIuiv wrap_glGetTexParameterIuiv -#define glGetTexParameterIuivEXT wrap_glGetTexParameterIuivEXT -#define glGetTexParameterIuivOES wrap_glGetTexParameterIuivOES -#define glGetTexParameterfv wrap_glGetTexParameterfv -#define glGetTexParameteriv wrap_glGetTexParameteriv -#define glGetTexParameterxv wrap_glGetTexParameterxv -#define glGetTexParameterxvOES wrap_glGetTexParameterxvOES -#define glGetTextureHandleNV wrap_glGetTextureHandleNV -#define glGetTextureSamplerHandleNV wrap_glGetTextureSamplerHandleNV -#define glGetTransformFeedbackVarying wrap_glGetTransformFeedbackVarying -#define glGetTranslatedShaderSourceANGLE wrap_glGetTranslatedShaderSourceANGLE -#define glGetUniformBlockIndex wrap_glGetUniformBlockIndex -#define glGetUniformIndices wrap_glGetUniformIndices -#define glGetUniformLocation wrap_glGetUniformLocation -#define glGetUniformfv wrap_glGetUniformfv -#define glGetUniformiv wrap_glGetUniformiv -#define glGetUniformuiv wrap_glGetUniformuiv -#define glGetVertexAttribIiv wrap_glGetVertexAttribIiv -#define glGetVertexAttribIuiv wrap_glGetVertexAttribIuiv -#define glGetVertexAttribPointerv wrap_glGetVertexAttribPointerv -#define glGetVertexAttribfv wrap_glGetVertexAttribfv -#define glGetVertexAttribiv wrap_glGetVertexAttribiv -#define glGetnUniformfv wrap_glGetnUniformfv -#define glGetnUniformfvEXT wrap_glGetnUniformfvEXT -#define glGetnUniformfvKHR wrap_glGetnUniformfvKHR -#define glGetnUniformiv wrap_glGetnUniformiv -#define glGetnUniformivEXT wrap_glGetnUniformivEXT -#define glGetnUniformivKHR wrap_glGetnUniformivKHR -#define glGetnUniformuiv wrap_glGetnUniformuiv -#define glGetnUniformuivKHR wrap_glGetnUniformuivKHR -#define glHint wrap_glHint -#define glInsertEventMarkerEXT wrap_glInsertEventMarkerEXT -#define glInterpolatePathsNV wrap_glInterpolatePathsNV -#define glInvalidateFramebuffer wrap_glInvalidateFramebuffer -#define glInvalidateSubFramebuffer wrap_glInvalidateSubFramebuffer -#define glIsBuffer wrap_glIsBuffer -#define glIsEnabled wrap_glIsEnabled -#define glIsEnabledi wrap_glIsEnabledi -#define glIsEnablediEXT wrap_glIsEnablediEXT -#define glIsEnablediNV wrap_glIsEnablediNV -#define glIsEnablediOES wrap_glIsEnablediOES -#define glIsFenceNV wrap_glIsFenceNV -#define glIsFramebuffer wrap_glIsFramebuffer -#define glIsFramebufferOES wrap_glIsFramebufferOES -#define glIsImageHandleResidentNV wrap_glIsImageHandleResidentNV -#define glIsPathNV wrap_glIsPathNV -#define glIsPointInFillPathNV wrap_glIsPointInFillPathNV -#define glIsPointInStrokePathNV wrap_glIsPointInStrokePathNV -#define glIsProgram wrap_glIsProgram -#define glIsProgramPipeline wrap_glIsProgramPipeline -#define glIsProgramPipelineEXT wrap_glIsProgramPipelineEXT -#define glIsQuery wrap_glIsQuery -#define glIsQueryEXT wrap_glIsQueryEXT -#define glIsRenderbuffer wrap_glIsRenderbuffer -#define glIsRenderbufferOES wrap_glIsRenderbufferOES -#define glIsSampler wrap_glIsSampler -#define glIsShader wrap_glIsShader -#define glIsSync wrap_glIsSync -#define glIsSyncAPPLE wrap_glIsSyncAPPLE -#define glIsTexture wrap_glIsTexture -#define glIsTextureHandleResidentNV wrap_glIsTextureHandleResidentNV -#define glIsTransformFeedback wrap_glIsTransformFeedback -#define glIsVertexArray wrap_glIsVertexArray -#define glIsVertexArrayOES wrap_glIsVertexArrayOES -#define glLabelObjectEXT wrap_glLabelObjectEXT -#define glLightModelf wrap_glLightModelf -#define glLightModelfv wrap_glLightModelfv -#define glLightModelx wrap_glLightModelx -#define glLightModelxOES wrap_glLightModelxOES -#define glLightModelxv wrap_glLightModelxv -#define glLightModelxvOES wrap_glLightModelxvOES -#define glLightf wrap_glLightf -#define glLightfv wrap_glLightfv -#define glLightx wrap_glLightx -#define glLightxOES wrap_glLightxOES -#define glLightxv wrap_glLightxv -#define glLightxvOES wrap_glLightxvOES -#define glLineWidth wrap_glLineWidth -#define glLineWidthx wrap_glLineWidthx -#define glLineWidthxOES wrap_glLineWidthxOES -#define glLinkProgram wrap_glLinkProgram -#define glLoadIdentity wrap_glLoadIdentity -#define glLoadMatrixf wrap_glLoadMatrixf -#define glLoadMatrixx wrap_glLoadMatrixx -#define glLoadMatrixxOES wrap_glLoadMatrixxOES -#define glLoadPaletteFromModelViewMatrixOES wrap_glLoadPaletteFromModelViewMatrixOES -#define glLogicOp wrap_glLogicOp -#define glMakeImageHandleNonResidentNV wrap_glMakeImageHandleNonResidentNV -#define glMakeImageHandleResidentNV wrap_glMakeImageHandleResidentNV -#define glMakeTextureHandleNonResidentNV wrap_glMakeTextureHandleNonResidentNV -#define glMakeTextureHandleResidentNV wrap_glMakeTextureHandleResidentNV -#define glMapBufferOES wrap_glMapBufferOES -#define glMapBufferRange wrap_glMapBufferRange -#define glMapBufferRangeEXT wrap_glMapBufferRangeEXT -#define glMaterialf wrap_glMaterialf -#define glMaterialfv wrap_glMaterialfv -#define glMaterialx wrap_glMaterialx -#define glMaterialxOES wrap_glMaterialxOES -#define glMaterialxv wrap_glMaterialxv -#define glMaterialxvOES wrap_glMaterialxvOES -#define glMatrixIndexPointerOES wrap_glMatrixIndexPointerOES -#define glMatrixLoad3x2fNV wrap_glMatrixLoad3x2fNV -#define glMatrixLoad3x3fNV wrap_glMatrixLoad3x3fNV -#define glMatrixLoadTranspose3x3fNV wrap_glMatrixLoadTranspose3x3fNV -#define glMatrixMode wrap_glMatrixMode -#define glMatrixMult3x2fNV wrap_glMatrixMult3x2fNV -#define glMatrixMult3x3fNV wrap_glMatrixMult3x3fNV -#define glMatrixMultTranspose3x3fNV wrap_glMatrixMultTranspose3x3fNV -#define glMemoryBarrier wrap_glMemoryBarrier -#define glMemoryBarrierByRegion wrap_glMemoryBarrierByRegion -#define glMinSampleShading wrap_glMinSampleShading -#define glMinSampleShadingOES wrap_glMinSampleShadingOES -#define glMultMatrixf wrap_glMultMatrixf -#define glMultMatrixx wrap_glMultMatrixx -#define glMultMatrixxOES wrap_glMultMatrixxOES -#define glMultiDrawArraysEXT wrap_glMultiDrawArraysEXT -#define glMultiDrawArraysIndirectEXT wrap_glMultiDrawArraysIndirectEXT -#define glMultiDrawElementsBaseVertexEXT wrap_glMultiDrawElementsBaseVertexEXT -#define glMultiDrawElementsBaseVertexOES wrap_glMultiDrawElementsBaseVertexOES -#define glMultiDrawElementsEXT wrap_glMultiDrawElementsEXT -#define glMultiDrawElementsIndirectEXT wrap_glMultiDrawElementsIndirectEXT -#define glMultiTexCoord4f wrap_glMultiTexCoord4f -#define glMultiTexCoord4x wrap_glMultiTexCoord4x -#define glMultiTexCoord4xOES wrap_glMultiTexCoord4xOES -#define glNamedFramebufferSampleLocationsfvNV wrap_glNamedFramebufferSampleLocationsfvNV -#define glNormal3f wrap_glNormal3f -#define glNormal3x wrap_glNormal3x -#define glNormal3xOES wrap_glNormal3xOES -#define glNormalPointer wrap_glNormalPointer -#define glObjectLabel wrap_glObjectLabel -#define glObjectLabelKHR wrap_glObjectLabelKHR -#define glObjectPtrLabel wrap_glObjectPtrLabel -#define glObjectPtrLabelKHR wrap_glObjectPtrLabelKHR -#define glOrthof wrap_glOrthof -#define glOrthofOES wrap_glOrthofOES -#define glOrthox wrap_glOrthox -#define glOrthoxOES wrap_glOrthoxOES -#define glPatchParameteri wrap_glPatchParameteri -#define glPatchParameteriEXT wrap_glPatchParameteriEXT -#define glPatchParameteriOES wrap_glPatchParameteriOES -#define glPathCommandsNV wrap_glPathCommandsNV -#define glPathCoordsNV wrap_glPathCoordsNV -#define glPathCoverDepthFuncNV wrap_glPathCoverDepthFuncNV -#define glPathDashArrayNV wrap_glPathDashArrayNV -#define glPathGlyphIndexArrayNV wrap_glPathGlyphIndexArrayNV -#define glPathGlyphIndexRangeNV wrap_glPathGlyphIndexRangeNV -#define glPathGlyphRangeNV wrap_glPathGlyphRangeNV -#define glPathGlyphsNV wrap_glPathGlyphsNV -#define glPathMemoryGlyphIndexArrayNV wrap_glPathMemoryGlyphIndexArrayNV -#define glPathParameterfNV wrap_glPathParameterfNV -#define glPathParameterfvNV wrap_glPathParameterfvNV -#define glPathParameteriNV wrap_glPathParameteriNV -#define glPathParameterivNV wrap_glPathParameterivNV -#define glPathStencilDepthOffsetNV wrap_glPathStencilDepthOffsetNV -#define glPathStencilFuncNV wrap_glPathStencilFuncNV -#define glPathStringNV wrap_glPathStringNV -#define glPathSubCommandsNV wrap_glPathSubCommandsNV -#define glPathSubCoordsNV wrap_glPathSubCoordsNV -#define glPauseTransformFeedback wrap_glPauseTransformFeedback -#define glPixelStorei wrap_glPixelStorei -#define glPointAlongPathNV wrap_glPointAlongPathNV -#define glPointParameterf wrap_glPointParameterf -#define glPointParameterfv wrap_glPointParameterfv -#define glPointParameterx wrap_glPointParameterx -#define glPointParameterxOES wrap_glPointParameterxOES -#define glPointParameterxv wrap_glPointParameterxv -#define glPointParameterxvOES wrap_glPointParameterxvOES -#define glPointSize wrap_glPointSize -#define glPointSizePointerOES wrap_glPointSizePointerOES -#define glPointSizex wrap_glPointSizex -#define glPointSizexOES wrap_glPointSizexOES -#define glPolygonModeNV wrap_glPolygonModeNV -#define glPolygonOffset wrap_glPolygonOffset -#define glPolygonOffsetx wrap_glPolygonOffsetx -#define glPolygonOffsetxOES wrap_glPolygonOffsetxOES -#define glPopDebugGroup wrap_glPopDebugGroup -#define glPopDebugGroupKHR wrap_glPopDebugGroupKHR -#define glPopGroupMarkerEXT wrap_glPopGroupMarkerEXT -#define glPopMatrix wrap_glPopMatrix -#define glPrimitiveBoundingBox wrap_glPrimitiveBoundingBox -#define glPrimitiveBoundingBoxEXT wrap_glPrimitiveBoundingBoxEXT -#define glPrimitiveBoundingBoxOES wrap_glPrimitiveBoundingBoxOES -#define glProgramBinary wrap_glProgramBinary -#define glProgramBinaryOES wrap_glProgramBinaryOES -#define glProgramParameteri wrap_glProgramParameteri -#define glProgramParameteriEXT wrap_glProgramParameteriEXT -#define glProgramPathFragmentInputGenNV wrap_glProgramPathFragmentInputGenNV -#define glProgramUniform1f wrap_glProgramUniform1f -#define glProgramUniform1fEXT wrap_glProgramUniform1fEXT -#define glProgramUniform1fv wrap_glProgramUniform1fv -#define glProgramUniform1fvEXT wrap_glProgramUniform1fvEXT -#define glProgramUniform1i wrap_glProgramUniform1i -#define glProgramUniform1iEXT wrap_glProgramUniform1iEXT -#define glProgramUniform1iv wrap_glProgramUniform1iv -#define glProgramUniform1ivEXT wrap_glProgramUniform1ivEXT -#define glProgramUniform1ui wrap_glProgramUniform1ui -#define glProgramUniform1uiEXT wrap_glProgramUniform1uiEXT -#define glProgramUniform1uiv wrap_glProgramUniform1uiv -#define glProgramUniform1uivEXT wrap_glProgramUniform1uivEXT -#define glProgramUniform2f wrap_glProgramUniform2f -#define glProgramUniform2fEXT wrap_glProgramUniform2fEXT -#define glProgramUniform2fv wrap_glProgramUniform2fv -#define glProgramUniform2fvEXT wrap_glProgramUniform2fvEXT -#define glProgramUniform2i wrap_glProgramUniform2i -#define glProgramUniform2iEXT wrap_glProgramUniform2iEXT -#define glProgramUniform2iv wrap_glProgramUniform2iv -#define glProgramUniform2ivEXT wrap_glProgramUniform2ivEXT -#define glProgramUniform2ui wrap_glProgramUniform2ui -#define glProgramUniform2uiEXT wrap_glProgramUniform2uiEXT -#define glProgramUniform2uiv wrap_glProgramUniform2uiv -#define glProgramUniform2uivEXT wrap_glProgramUniform2uivEXT -#define glProgramUniform3f wrap_glProgramUniform3f -#define glProgramUniform3fEXT wrap_glProgramUniform3fEXT -#define glProgramUniform3fv wrap_glProgramUniform3fv -#define glProgramUniform3fvEXT wrap_glProgramUniform3fvEXT -#define glProgramUniform3i wrap_glProgramUniform3i -#define glProgramUniform3iEXT wrap_glProgramUniform3iEXT -#define glProgramUniform3iv wrap_glProgramUniform3iv -#define glProgramUniform3ivEXT wrap_glProgramUniform3ivEXT -#define glProgramUniform3ui wrap_glProgramUniform3ui -#define glProgramUniform3uiEXT wrap_glProgramUniform3uiEXT -#define glProgramUniform3uiv wrap_glProgramUniform3uiv -#define glProgramUniform3uivEXT wrap_glProgramUniform3uivEXT -#define glProgramUniform4f wrap_glProgramUniform4f -#define glProgramUniform4fEXT wrap_glProgramUniform4fEXT -#define glProgramUniform4fv wrap_glProgramUniform4fv -#define glProgramUniform4fvEXT wrap_glProgramUniform4fvEXT -#define glProgramUniform4i wrap_glProgramUniform4i -#define glProgramUniform4iEXT wrap_glProgramUniform4iEXT -#define glProgramUniform4iv wrap_glProgramUniform4iv -#define glProgramUniform4ivEXT wrap_glProgramUniform4ivEXT -#define glProgramUniform4ui wrap_glProgramUniform4ui -#define glProgramUniform4uiEXT wrap_glProgramUniform4uiEXT -#define glProgramUniform4uiv wrap_glProgramUniform4uiv -#define glProgramUniform4uivEXT wrap_glProgramUniform4uivEXT -#define glProgramUniformHandleui64NV wrap_glProgramUniformHandleui64NV -#define glProgramUniformHandleui64vNV wrap_glProgramUniformHandleui64vNV -#define glProgramUniformMatrix2fv wrap_glProgramUniformMatrix2fv -#define glProgramUniformMatrix2fvEXT wrap_glProgramUniformMatrix2fvEXT -#define glProgramUniformMatrix2x3fv wrap_glProgramUniformMatrix2x3fv -#define glProgramUniformMatrix2x3fvEXT wrap_glProgramUniformMatrix2x3fvEXT -#define glProgramUniformMatrix2x4fv wrap_glProgramUniformMatrix2x4fv -#define glProgramUniformMatrix2x4fvEXT wrap_glProgramUniformMatrix2x4fvEXT -#define glProgramUniformMatrix3fv wrap_glProgramUniformMatrix3fv -#define glProgramUniformMatrix3fvEXT wrap_glProgramUniformMatrix3fvEXT -#define glProgramUniformMatrix3x2fv wrap_glProgramUniformMatrix3x2fv -#define glProgramUniformMatrix3x2fvEXT wrap_glProgramUniformMatrix3x2fvEXT -#define glProgramUniformMatrix3x4fv wrap_glProgramUniformMatrix3x4fv -#define glProgramUniformMatrix3x4fvEXT wrap_glProgramUniformMatrix3x4fvEXT -#define glProgramUniformMatrix4fv wrap_glProgramUniformMatrix4fv -#define glProgramUniformMatrix4fvEXT wrap_glProgramUniformMatrix4fvEXT -#define glProgramUniformMatrix4x2fv wrap_glProgramUniformMatrix4x2fv -#define glProgramUniformMatrix4x2fvEXT wrap_glProgramUniformMatrix4x2fvEXT -#define glProgramUniformMatrix4x3fv wrap_glProgramUniformMatrix4x3fv -#define glProgramUniformMatrix4x3fvEXT wrap_glProgramUniformMatrix4x3fvEXT -#define glPushDebugGroup wrap_glPushDebugGroup -#define glPushDebugGroupKHR wrap_glPushDebugGroupKHR -#define glPushGroupMarkerEXT wrap_glPushGroupMarkerEXT -#define glPushMatrix wrap_glPushMatrix -#define glQueryCounterEXT wrap_glQueryCounterEXT -#define glQueryMatrixxOES wrap_glQueryMatrixxOES -#define glRasterSamplesEXT wrap_glRasterSamplesEXT -#define glReadBuffer wrap_glReadBuffer -#define glReadBufferIndexedEXT wrap_glReadBufferIndexedEXT -#define glReadBufferNV wrap_glReadBufferNV -#define glReadPixels wrap_glReadPixels -#define glReadnPixels wrap_glReadnPixels -#define glReadnPixelsEXT wrap_glReadnPixelsEXT -#define glReadnPixelsKHR wrap_glReadnPixelsKHR -#define glReleaseShaderCompiler wrap_glReleaseShaderCompiler -#define glRenderbufferStorage wrap_glRenderbufferStorage -#define glRenderbufferStorageMultisample wrap_glRenderbufferStorageMultisample -#define glRenderbufferStorageMultisampleANGLE wrap_glRenderbufferStorageMultisampleANGLE -#define glRenderbufferStorageMultisampleAPPLE wrap_glRenderbufferStorageMultisampleAPPLE -#define glRenderbufferStorageMultisampleEXT wrap_glRenderbufferStorageMultisampleEXT -#define glRenderbufferStorageMultisampleIMG wrap_glRenderbufferStorageMultisampleIMG -#define glRenderbufferStorageMultisampleNV wrap_glRenderbufferStorageMultisampleNV -#define glRenderbufferStorageOES wrap_glRenderbufferStorageOES -#define glResolveDepthValuesNV wrap_glResolveDepthValuesNV -#define glResolveMultisampleFramebufferAPPLE wrap_glResolveMultisampleFramebufferAPPLE -#define glResumeTransformFeedback wrap_glResumeTransformFeedback -#define glRotatef wrap_glRotatef -#define glRotatex wrap_glRotatex -#define glRotatexOES wrap_glRotatexOES -#define glSampleCoverage wrap_glSampleCoverage -#define glSampleCoveragex wrap_glSampleCoveragex -#define glSampleCoveragexOES wrap_glSampleCoveragexOES -#define glSampleMaski wrap_glSampleMaski -#define glSamplerParameterIiv wrap_glSamplerParameterIiv -#define glSamplerParameterIivEXT wrap_glSamplerParameterIivEXT -#define glSamplerParameterIivOES wrap_glSamplerParameterIivOES -#define glSamplerParameterIuiv wrap_glSamplerParameterIuiv -#define glSamplerParameterIuivEXT wrap_glSamplerParameterIuivEXT -#define glSamplerParameterIuivOES wrap_glSamplerParameterIuivOES -#define glSamplerParameterf wrap_glSamplerParameterf -#define glSamplerParameterfv wrap_glSamplerParameterfv -#define glSamplerParameteri wrap_glSamplerParameteri -#define glSamplerParameteriv wrap_glSamplerParameteriv -#define glScalef wrap_glScalef -#define glScalex wrap_glScalex -#define glScalexOES wrap_glScalexOES -#define glScissor wrap_glScissor -#define glScissorArrayvNV wrap_glScissorArrayvNV -#define glScissorIndexedNV wrap_glScissorIndexedNV -#define glScissorIndexedvNV wrap_glScissorIndexedvNV -#define glSelectPerfMonitorCountersAMD wrap_glSelectPerfMonitorCountersAMD -#define glSetFenceNV wrap_glSetFenceNV -#define glShadeModel wrap_glShadeModel -#define glShaderBinary wrap_glShaderBinary -#define glShaderSource wrap_glShaderSource -#define glStartTilingQCOM wrap_glStartTilingQCOM -#define glStencilFillPathInstancedNV wrap_glStencilFillPathInstancedNV -#define glStencilFillPathNV wrap_glStencilFillPathNV -#define glStencilFunc wrap_glStencilFunc -#define glStencilFuncSeparate wrap_glStencilFuncSeparate -#define glStencilMask wrap_glStencilMask -#define glStencilMaskSeparate wrap_glStencilMaskSeparate -#define glStencilOp wrap_glStencilOp -#define glStencilOpSeparate wrap_glStencilOpSeparate -#define glStencilStrokePathInstancedNV wrap_glStencilStrokePathInstancedNV -#define glStencilStrokePathNV wrap_glStencilStrokePathNV -#define glStencilThenCoverFillPathInstancedNV wrap_glStencilThenCoverFillPathInstancedNV -#define glStencilThenCoverFillPathNV wrap_glStencilThenCoverFillPathNV -#define glStencilThenCoverStrokePathInstancedNV wrap_glStencilThenCoverStrokePathInstancedNV -#define glStencilThenCoverStrokePathNV wrap_glStencilThenCoverStrokePathNV -#define glSubpixelPrecisionBiasNV wrap_glSubpixelPrecisionBiasNV -#define glTestFenceNV wrap_glTestFenceNV -#define glTexBuffer wrap_glTexBuffer -#define glTexBufferEXT wrap_glTexBufferEXT -#define glTexBufferOES wrap_glTexBufferOES -#define glTexBufferRange wrap_glTexBufferRange -#define glTexBufferRangeEXT wrap_glTexBufferRangeEXT -#define glTexBufferRangeOES wrap_glTexBufferRangeOES -#define glTexCoordPointer wrap_glTexCoordPointer -#define glTexEnvf wrap_glTexEnvf -#define glTexEnvfv wrap_glTexEnvfv -#define glTexEnvi wrap_glTexEnvi -#define glTexEnviv wrap_glTexEnviv -#define glTexEnvx wrap_glTexEnvx -#define glTexEnvxOES wrap_glTexEnvxOES -#define glTexEnvxv wrap_glTexEnvxv -#define glTexEnvxvOES wrap_glTexEnvxvOES -#define glTexGenfOES wrap_glTexGenfOES -#define glTexGenfvOES wrap_glTexGenfvOES -#define glTexGeniOES wrap_glTexGeniOES -#define glTexGenivOES wrap_glTexGenivOES -#define glTexGenxOES wrap_glTexGenxOES -#define glTexGenxvOES wrap_glTexGenxvOES -#define glTexImage2D wrap_glTexImage2D -#define glTexImage3D wrap_glTexImage3D -#define glTexImage3DOES wrap_glTexImage3DOES -#define glTexPageCommitmentEXT wrap_glTexPageCommitmentEXT -#define glTexParameterIiv wrap_glTexParameterIiv -#define glTexParameterIivEXT wrap_glTexParameterIivEXT -#define glTexParameterIivOES wrap_glTexParameterIivOES -#define glTexParameterIuiv wrap_glTexParameterIuiv -#define glTexParameterIuivEXT wrap_glTexParameterIuivEXT -#define glTexParameterIuivOES wrap_glTexParameterIuivOES -#define glTexParameterf wrap_glTexParameterf -#define glTexParameterfv wrap_glTexParameterfv -#define glTexParameteri wrap_glTexParameteri -#define glTexParameteriv wrap_glTexParameteriv -#define glTexParameterx wrap_glTexParameterx -#define glTexParameterxOES wrap_glTexParameterxOES -#define glTexParameterxv wrap_glTexParameterxv -#define glTexParameterxvOES wrap_glTexParameterxvOES -#define glTexStorage1DEXT wrap_glTexStorage1DEXT -#define glTexStorage2D wrap_glTexStorage2D -#define glTexStorage2DEXT wrap_glTexStorage2DEXT -#define glTexStorage2DMultisample wrap_glTexStorage2DMultisample -#define glTexStorage3D wrap_glTexStorage3D -#define glTexStorage3DEXT wrap_glTexStorage3DEXT -#define glTexStorage3DMultisample wrap_glTexStorage3DMultisample -#define glTexStorage3DMultisampleOES wrap_glTexStorage3DMultisampleOES -#define glTexSubImage2D wrap_glTexSubImage2D -#define glTexSubImage3D wrap_glTexSubImage3D -#define glTexSubImage3DOES wrap_glTexSubImage3DOES -#define glTextureStorage1DEXT wrap_glTextureStorage1DEXT -#define glTextureStorage2DEXT wrap_glTextureStorage2DEXT -#define glTextureStorage3DEXT wrap_glTextureStorage3DEXT -#define glTextureViewEXT wrap_glTextureViewEXT -#define glTextureViewOES wrap_glTextureViewOES -#define glTransformFeedbackVaryings wrap_glTransformFeedbackVaryings -#define glTransformPathNV wrap_glTransformPathNV -#define glTranslatef wrap_glTranslatef -#define glTranslatex wrap_glTranslatex -#define glTranslatexOES wrap_glTranslatexOES -#define glUniform1f wrap_glUniform1f -#define glUniform1fv wrap_glUniform1fv -#define glUniform1i wrap_glUniform1i -#define glUniform1iv wrap_glUniform1iv -#define glUniform1ui wrap_glUniform1ui -#define glUniform1uiv wrap_glUniform1uiv -#define glUniform2f wrap_glUniform2f -#define glUniform2fv wrap_glUniform2fv -#define glUniform2i wrap_glUniform2i -#define glUniform2iv wrap_glUniform2iv -#define glUniform2ui wrap_glUniform2ui -#define glUniform2uiv wrap_glUniform2uiv -#define glUniform3f wrap_glUniform3f -#define glUniform3fv wrap_glUniform3fv -#define glUniform3i wrap_glUniform3i -#define glUniform3iv wrap_glUniform3iv -#define glUniform3ui wrap_glUniform3ui -#define glUniform3uiv wrap_glUniform3uiv -#define glUniform4f wrap_glUniform4f -#define glUniform4fv wrap_glUniform4fv -#define glUniform4i wrap_glUniform4i -#define glUniform4iv wrap_glUniform4iv -#define glUniform4ui wrap_glUniform4ui -#define glUniform4uiv wrap_glUniform4uiv -#define glUniformBlockBinding wrap_glUniformBlockBinding -#define glUniformHandleui64NV wrap_glUniformHandleui64NV -#define glUniformHandleui64vNV wrap_glUniformHandleui64vNV -#define glUniformMatrix2fv wrap_glUniformMatrix2fv -#define glUniformMatrix2x3fv wrap_glUniformMatrix2x3fv -#define glUniformMatrix2x3fvNV wrap_glUniformMatrix2x3fvNV -#define glUniformMatrix2x4fv wrap_glUniformMatrix2x4fv -#define glUniformMatrix2x4fvNV wrap_glUniformMatrix2x4fvNV -#define glUniformMatrix3fv wrap_glUniformMatrix3fv -#define glUniformMatrix3x2fv wrap_glUniformMatrix3x2fv -#define glUniformMatrix3x2fvNV wrap_glUniformMatrix3x2fvNV -#define glUniformMatrix3x4fv wrap_glUniformMatrix3x4fv -#define glUniformMatrix3x4fvNV wrap_glUniformMatrix3x4fvNV -#define glUniformMatrix4fv wrap_glUniformMatrix4fv -#define glUniformMatrix4x2fv wrap_glUniformMatrix4x2fv -#define glUniformMatrix4x2fvNV wrap_glUniformMatrix4x2fvNV -#define glUniformMatrix4x3fv wrap_glUniformMatrix4x3fv -#define glUniformMatrix4x3fvNV wrap_glUniformMatrix4x3fvNV -#define glUnmapBuffer wrap_glUnmapBuffer -#define glUnmapBufferOES wrap_glUnmapBufferOES -#define glUseProgram wrap_glUseProgram -#define glUseProgramStages wrap_glUseProgramStages -#define glUseProgramStagesEXT wrap_glUseProgramStagesEXT -#define glValidateProgram wrap_glValidateProgram -#define glValidateProgramPipeline wrap_glValidateProgramPipeline -#define glValidateProgramPipelineEXT wrap_glValidateProgramPipelineEXT -#define glVertexAttrib1f wrap_glVertexAttrib1f -#define glVertexAttrib1fv wrap_glVertexAttrib1fv -#define glVertexAttrib2f wrap_glVertexAttrib2f -#define glVertexAttrib2fv wrap_glVertexAttrib2fv -#define glVertexAttrib3f wrap_glVertexAttrib3f -#define glVertexAttrib3fv wrap_glVertexAttrib3fv -#define glVertexAttrib4f wrap_glVertexAttrib4f -#define glVertexAttrib4fv wrap_glVertexAttrib4fv -#define glVertexAttribBinding wrap_glVertexAttribBinding -#define glVertexAttribDivisor wrap_glVertexAttribDivisor -#define glVertexAttribDivisorANGLE wrap_glVertexAttribDivisorANGLE -#define glVertexAttribDivisorEXT wrap_glVertexAttribDivisorEXT -#define glVertexAttribDivisorNV wrap_glVertexAttribDivisorNV -#define glVertexAttribFormat wrap_glVertexAttribFormat -#define glVertexAttribI4i wrap_glVertexAttribI4i -#define glVertexAttribI4iv wrap_glVertexAttribI4iv -#define glVertexAttribI4ui wrap_glVertexAttribI4ui -#define glVertexAttribI4uiv wrap_glVertexAttribI4uiv -#define glVertexAttribIFormat wrap_glVertexAttribIFormat -#define glVertexAttribIPointer wrap_glVertexAttribIPointer -#define glVertexAttribPointer wrap_glVertexAttribPointer -#define glVertexBindingDivisor wrap_glVertexBindingDivisor -#define glVertexPointer wrap_glVertexPointer -#define glViewport wrap_glViewport -#define glViewportArrayvNV wrap_glViewportArrayvNV -#define glViewportIndexedfNV wrap_glViewportIndexedfNV -#define glViewportIndexedfvNV wrap_glViewportIndexedfvNV -#define glWaitSync wrap_glWaitSync -#define glWaitSyncAPPLE wrap_glWaitSyncAPPLE -#define glWeightPathsNV wrap_glWeightPathsNV -#define glWeightPointerOES wrap_glWeightPointerOES +#include "GlesDriver.h" -#endif // HWUI_GLES_WRAP_ENABLED +#define GL_ENTRY(ret, api, ...) ret api(__VA_ARGS__); + +#include "gles_decls.in" +#undef GL_ENTRY diff --git a/libs/hwui/font/CachedGlyphInfo.h b/libs/hwui/font/CachedGlyphInfo.h index 0642d59d9b16..073d59bdea3f 100644 --- a/libs/hwui/font/CachedGlyphInfo.h +++ b/libs/hwui/font/CachedGlyphInfo.h @@ -17,8 +17,6 @@ #ifndef ANDROID_HWUI_CACHED_GLYPH_INFO_H #define ANDROID_HWUI_CACHED_GLYPH_INFO_H -#include <SkFixed.h> - namespace android { namespace uirenderer { @@ -41,14 +39,14 @@ struct CachedGlyphInfo { float mBitmapMaxV; // Minimize how much we call freetype uint32_t mGlyphIndex; - uint32_t mAdvanceX; - uint32_t mAdvanceY; + float mAdvanceX; + float mAdvanceY; // Values below contain a glyph's origin in the bitmap int32_t mBitmapLeft; int32_t mBitmapTop; - // Auto-kerning - SkFixed mLsbDelta; - SkFixed mRsbDelta; + // Auto-kerning; represents a 2.6 fixed-point value with range [-1, 1]. + int8_t mLsbDelta; + int8_t mRsbDelta; CacheTexture* mCacheTexture; }; diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp index 8e04c8715f62..9c812bc33e46 100644 --- a/libs/hwui/font/Font.cpp +++ b/libs/hwui/font/Font.cpp @@ -304,7 +304,7 @@ void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, } int glyphsCount = 0; - SkFixed prevRsbDelta = 0; + int prevRsbDelta = 0; float penX = 0.0f; @@ -332,14 +332,14 @@ void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, } CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); - penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta)); + penX += AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta); prevRsbDelta = cachedGlyph->mRsbDelta; if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) { drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent); } - penX += SkFixedToFloat(cachedGlyph->mAdvanceX); + penX += cachedGlyph->mAdvanceX; glyphsCount++; } diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h index aa77d98c9343..07e8b34ac66f 100644 --- a/libs/hwui/font/FontUtil.h +++ b/libs/hwui/font/FontUtil.h @@ -44,6 +44,8 @@ typedef uint16_t glyph_t; #define GET_METRICS(cache, glyph) cache->getGlyphIDMetrics(glyph) #define IS_END_OF_STRING(glyph) false -#define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16) +// prev, next are assumed to be signed x.6 fixed-point numbers with range +// [-1, 1]. Result is an integral float. +#define AUTO_KERN(prev, next) static_cast<float>(((next) - (prev) + 32) >> 6) #endif // ANDROID_HWUI_FONT_UTIL_H diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index 7bfa15a26d56..461363f5e8d8 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -16,7 +16,6 @@ #include "Canvas.h" -#include "DisplayListCanvas.h" #include "RecordingCanvas.h" #include "MinikinUtils.h" #include "Paint.h" @@ -27,11 +26,7 @@ namespace android { Canvas* Canvas::create_recording_canvas(int width, int height) { -#if HWUI_NEW_OPS return new uirenderer::RecordingCanvas(width, height); -#else - return new uirenderer::DisplayListCanvas(width, height); -#endif } void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { @@ -79,8 +74,9 @@ static void simplifyPaint(int color, SkPaint* paint) { class DrawTextFunctor { public: - DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos, - const SkPaint& paint, float x, float y, MinikinRect& bounds, float totalAdvance) + DrawTextFunctor(const minikin::Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos, + const SkPaint& paint, float x, float y, minikin::MinikinRect& bounds, + float totalAdvance) : layout(layout) , canvas(canvas) , glyphs(glyphs) @@ -135,14 +131,14 @@ public: } } private: - const Layout& layout; + const minikin::Layout& layout; Canvas* canvas; uint16_t* glyphs; float* pos; const SkPaint& paint; float x; float y; - MinikinRect& bounds; + minikin::MinikinRect& bounds; float totalAdvance; }; @@ -151,7 +147,7 @@ void Canvas::drawText(const uint16_t* text, int start, int count, int contextCou // minikin may modify the original paint Paint paint(origPaint); - Layout layout; + minikin::Layout layout; MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount); size_t nGlyphs = layout.nGlyphs(); @@ -160,7 +156,7 @@ void Canvas::drawText(const uint16_t* text, int start, int count, int contextCou x += MinikinUtils::xOffsetForTextAlign(&paint, layout); - MinikinRect bounds; + minikin::MinikinRect bounds; layout.getBounds(&bounds); if (!drawTextAbsolutePos()) { bounds.offset(x, y); @@ -178,7 +174,7 @@ void Canvas::drawText(const uint16_t* text, int start, int count, int contextCou class DrawTextOnPathFunctor { public: - DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset, + DrawTextOnPathFunctor(const minikin::Layout& layout, Canvas* canvas, float hOffset, float vOffset, const Paint& paint, const SkPath& path) : layout(layout) , canvas(canvas) @@ -198,7 +194,7 @@ public: } } private: - const Layout& layout; + const minikin::Layout& layout; Canvas* canvas; float hOffset; float vOffset; @@ -209,7 +205,7 @@ private: void Canvas::drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path, float hOffset, float vOffset, const Paint& paint, Typeface* typeface) { Paint paintCopy(paint); - Layout layout; + minikin::Layout layout; MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count); hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path); diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 55af33e80256..0b4209925bd4 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_GRAPHICS_CANVAS_H -#define ANDROID_GRAPHICS_CANVAS_H +#pragma once #include <cutils/compiler.h> #include <utils/Functor.h> @@ -220,7 +219,7 @@ public: /** * Draws a VectorDrawable onto the canvas. */ - virtual void drawVectorDrawable(VectorDrawableRoot* tree); + virtual void drawVectorDrawable(VectorDrawableRoot* tree) = 0; /** * Converts utf16 text to glyphs, calculating position and boundary, @@ -253,4 +252,3 @@ protected: }; }; // namespace android -#endif // ANDROID_GRAPHICS_CANVAS_H diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp index a455f576e38d..d16b64415f52 100644 --- a/libs/hwui/hwui/MinikinSkia.cpp +++ b/libs/hwui/hwui/MinikinSkia.cpp @@ -24,7 +24,7 @@ namespace android { MinikinFontSkia::MinikinFontSkia(SkTypeface* typeface, const void* fontData, size_t fontSize, int ttcIndex) : - MinikinFont(typeface->uniqueID()), mTypeface(typeface), mFontData(fontData), + minikin::MinikinFont(typeface->uniqueID()), mTypeface(typeface), mFontData(fontData), mFontSize(fontSize), mTtcIndex(ttcIndex) { } @@ -32,7 +32,8 @@ MinikinFontSkia::~MinikinFontSkia() { SkSafeUnref(mTypeface); } -static void MinikinFontSkia_SetSkiaPaint(const MinikinFont* font, SkPaint* skPaint, const MinikinPaint& paint) { +static void MinikinFontSkia_SetSkiaPaint(const minikin::MinikinFont* font, SkPaint* skPaint, + const minikin::MinikinPaint& paint) { skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); skPaint->setTextSize(paint.size); skPaint->setTextScaleX(paint.scaleX); @@ -43,7 +44,7 @@ static void MinikinFontSkia_SetSkiaPaint(const MinikinFont* font, SkPaint* skPai } float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id, - const MinikinPaint &paint) const { + const minikin::MinikinPaint &paint) const { SkPaint skPaint; uint16_t glyph16 = glyph_id; SkScalar skWidth; @@ -55,8 +56,8 @@ float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id, return skWidth; } -void MinikinFontSkia::GetBounds(MinikinRect* bounds, uint32_t glyph_id, - const MinikinPaint& paint) const { +void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, + const minikin::MinikinPaint& paint) const { SkPaint skPaint; uint16_t glyph16 = glyph_id; SkRect skBounds; @@ -68,7 +69,8 @@ void MinikinFontSkia::GetBounds(MinikinRect* bounds, uint32_t glyph_id, bounds->mBottom = skBounds.fBottom; } -const void* MinikinFontSkia::GetTable(uint32_t tag, size_t* size, MinikinDestroyFunc* destroy) { +const void* MinikinFontSkia::GetTable(uint32_t tag, size_t* size, + minikin::MinikinDestroyFunc* destroy) { // we don't have a buffer to the font data, copy to own buffer const size_t tableSize = mTypeface->getTableSize(tag); *size = tableSize; @@ -117,7 +119,8 @@ void MinikinFontSkia::unpackPaintFlags(SkPaint* paint, uint32_t paintFlags) { paint->setHinting(static_cast<SkPaint::Hinting>(paintFlags >> 16)); } -void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery) { +void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font, + minikin::FontFakery fakery) { paint->setTypeface(reinterpret_cast<const MinikinFontSkia*>(font)->GetSkTypeface()); paint->setFakeBoldText(paint->isFakeBoldText() || fakery.isFakeBold()); if (fakery.isFakeItalic()) { diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h index a7c9fb0b09d4..96b256d1b8af 100644 --- a/libs/hwui/hwui/MinikinSkia.h +++ b/libs/hwui/hwui/MinikinSkia.h @@ -25,7 +25,7 @@ class SkTypeface; namespace android { -class ANDROID_API MinikinFontSkia : public MinikinFont { +class ANDROID_API MinikinFontSkia : public minikin::MinikinFont { public: // Note: this takes ownership of the reference (will unref on dtor) explicit MinikinFontSkia(SkTypeface *typeface, const void* fontData, size_t fontSize, @@ -34,12 +34,12 @@ public: ~MinikinFontSkia(); float GetHorizontalAdvance(uint32_t glyph_id, - const MinikinPaint &paint) const; + const minikin::MinikinPaint &paint) const; - void GetBounds(MinikinRect* bounds, uint32_t glyph_id, - const MinikinPaint &paint) const; + void GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id, + const minikin::MinikinPaint &paint) const; - const void* GetTable(uint32_t tag, size_t* size, MinikinDestroyFunc* destroy); + const void* GetTable(uint32_t tag, size_t* size, minikin::MinikinDestroyFunc* destroy); SkTypeface* GetSkTypeface() const; @@ -52,7 +52,8 @@ public: static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags); // set typeface and fake bold/italic parameters - static void populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery); + static void populateSkPaint(SkPaint* paint, const minikin::MinikinFont* font, + minikin::FontFakery fakery); private: SkTypeface* mTypeface; diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp index 67b775d98356..a06cc37f944e 100644 --- a/libs/hwui/hwui/MinikinUtils.cpp +++ b/libs/hwui/hwui/MinikinUtils.cpp @@ -24,17 +24,18 @@ namespace android { -FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont, - const Paint* paint, Typeface* typeface) { +minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* minikinPaint, + minikin::FontCollection** pFont, const Paint* paint, Typeface* typeface) { const Typeface* resolvedFace = Typeface::resolveDefault(typeface); *pFont = resolvedFace->fFontCollection; - FontStyle resolved = resolvedFace->fStyle; + minikin::FontStyle resolved = resolvedFace->fStyle; /* Prepare minikin FontStyle */ - FontVariant minikinVariant = (paint->getFontVariant() == VARIANT_ELEGANT) ? VARIANT_ELEGANT - : VARIANT_COMPACT; + minikin::FontVariant minikinVariant = (paint->getFontVariant() == minikin::VARIANT_ELEGANT) ? + minikin::VARIANT_ELEGANT : minikin::VARIANT_COMPACT; const uint32_t langListId = paint->getMinikinLangListId(); - FontStyle minikinStyle(langListId, minikinVariant, resolved.getWeight(), resolved.getItalic()); + minikin::FontStyle minikinStyle(langListId, minikinVariant, resolved.getWeight(), + resolved.getItalic()); /* Prepare minikin Paint */ // Note: it would be nice to handle fractional size values (it would improve smooth zoom @@ -46,27 +47,27 @@ FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontColl minikinPaint->letterSpacing = paint->getLetterSpacing(); minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint); minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings(); - minikinPaint->hyphenEdit = HyphenEdit(paint->getHyphenEdit()); + minikinPaint->hyphenEdit = minikin::HyphenEdit(paint->getHyphenEdit()); return minikinStyle; } -void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, +void MinikinUtils::doLayout(minikin::Layout* layout, const Paint* paint, int bidiFlags, Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize) { - FontCollection *font; - MinikinPaint minikinPaint; - FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface); + minikin::FontCollection *font; + minikin::MinikinPaint minikinPaint; + minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface); layout->setFontCollection(font); layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint); } float MinikinUtils::measureText(const Paint* paint, int bidiFlags, Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances) { - FontCollection *font; - MinikinPaint minikinPaint; - FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface); - return Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint, - font, advances); + minikin::FontCollection *font; + minikin::MinikinPaint minikinPaint; + minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface); + return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle, + minikinPaint, font, advances); } bool MinikinUtils::hasVariationSelector(Typeface* typeface, uint32_t codepoint, uint32_t vs) { @@ -74,7 +75,7 @@ bool MinikinUtils::hasVariationSelector(Typeface* typeface, uint32_t codepoint, return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs); } -float MinikinUtils::xOffsetForTextAlign(Paint* paint, const Layout& layout) { +float MinikinUtils::xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout) { switch (paint->getTextAlign()) { case Paint::kCenter_Align: return layout.getAdvance() * -0.5f; @@ -88,7 +89,8 @@ float MinikinUtils::xOffsetForTextAlign(Paint* paint, const Layout& layout) { return 0; } -float MinikinUtils::hOffsetForTextAlign(Paint* paint, const Layout& layout, const SkPath& path) { +float MinikinUtils::hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout, + const SkPath& path) { float align = 0; switch (paint->getTextAlign()) { case Paint::kCenter_Align: diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h index cfaa961ac1fc..d6f64d2418d5 100644 --- a/libs/hwui/hwui/MinikinUtils.h +++ b/libs/hwui/hwui/MinikinUtils.h @@ -34,31 +34,33 @@ namespace android { class MinikinUtils { public: - ANDROID_API static FontStyle prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont, - const Paint* paint, Typeface* typeface); + ANDROID_API static minikin::FontStyle prepareMinikinPaint(minikin::MinikinPaint* minikinPaint, + minikin::FontCollection** pFont, const Paint* paint, Typeface* typeface); - ANDROID_API static void doLayout(Layout* layout, const Paint* paint, int bidiFlags, + ANDROID_API static void doLayout(minikin::Layout* layout, const Paint* paint, int bidiFlags, Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize); ANDROID_API static float measureText(const Paint* paint, int bidiFlags, Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances); - ANDROID_API static bool hasVariationSelector(Typeface* typeface, uint32_t codepoint, uint32_t vs); + ANDROID_API static bool hasVariationSelector(Typeface* typeface, uint32_t codepoint, + uint32_t vs); - ANDROID_API static float xOffsetForTextAlign(Paint* paint, const Layout& layout); + ANDROID_API static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout); - ANDROID_API static float hOffsetForTextAlign(Paint* paint, const Layout& layout, const SkPath& path); + ANDROID_API static float hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout, + const SkPath& path); // f is a functor of type void f(size_t start, size_t end); template <typename F> - ANDROID_API static void forFontRun(const Layout& layout, Paint* paint, F& f) { + ANDROID_API static void forFontRun(const minikin::Layout& layout, Paint* paint, F& f) { float saveSkewX = paint->getTextSkewX(); bool savefakeBold = paint->isFakeBoldText(); - MinikinFont* curFont = NULL; + minikin::MinikinFont* curFont = NULL; size_t start = 0; size_t nGlyphs = layout.nGlyphs(); for (size_t i = 0; i < nGlyphs; i++) { - MinikinFont* nextFont = layout.getFont(i); + minikin::MinikinFont* nextFont = layout.getFont(i); if (i > 0 && nextFont != curFont) { MinikinFontSkia::populateSkPaint(paint, curFont, layout.getFakery(start)); f(start, i); diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h index 9599c30c639b..6307926ec43e 100644 --- a/libs/hwui/hwui/Paint.h +++ b/libs/hwui/hwui/Paint.h @@ -64,11 +64,11 @@ public: return mMinikinLangListId; } - void setFontVariant(FontVariant variant) { + void setFontVariant(minikin::FontVariant variant) { mFontVariant = variant; } - FontVariant getFontVariant() const { + minikin::FontVariant getFontVariant() const { return mFontVariant; } @@ -84,7 +84,7 @@ private: float mLetterSpacing = 0; std::string mFontFeatureSettings; uint32_t mMinikinLangListId; - FontVariant mFontVariant; + minikin::FontVariant mFontVariant; uint32_t mHyphenEdit = 0; }; diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp index b27672ce16a0..84122d768089 100644 --- a/libs/hwui/hwui/PaintImpl.cpp +++ b/libs/hwui/hwui/PaintImpl.cpp @@ -20,7 +20,7 @@ namespace android { Paint::Paint() : SkPaint(), mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0), - mFontVariant(VARIANT_DEFAULT) { + mFontVariant(minikin::VARIANT_DEFAULT) { } Paint::Paint(const Paint& paint) : SkPaint(paint), @@ -31,7 +31,7 @@ Paint::Paint(const Paint& paint) : SkPaint(paint), Paint::Paint(const SkPaint& paint) : SkPaint(paint), mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0), - mFontVariant(VARIANT_DEFAULT) { + mFontVariant(minikin::VARIANT_DEFAULT) { } Paint::~Paint() { diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp index c583988554c7..b5c5ef9a5915 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -43,7 +43,7 @@ static void resolveStyle(Typeface* typeface) { weight = 9; } bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0; - typeface->fStyle = FontStyle(weight, italic); + typeface->fStyle = minikin::FontStyle(weight, italic); } Typeface* gDefaultTypeface = NULL; @@ -54,13 +54,13 @@ pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT; // typeface is set. // TODO: investigate why layouts are being created before Typeface.java // class initialization. -static FontCollection *makeFontCollection() { - std::vector<FontFamily *>typefaces; +static minikin::FontCollection *makeFontCollection() { + std::vector<minikin::FontFamily *>typefaces; const char *fns[] = { "/system/fonts/Roboto-Regular.ttf", }; - FontFamily *family = new FontFamily(); + minikin::FontFamily *family = new minikin::FontFamily(); for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) { const char *fn = fns[i]; ALOGD("makeFontCollection adding %s", fn); @@ -69,7 +69,7 @@ static FontCollection *makeFontCollection() { // TODO: might be a nice optimization to get access to the underlying font // data, but would require us opening the file ourselves and passing that // to the appropriate Create method of SkTypeface. - MinikinFont *font = new MinikinFontSkia(skFace, NULL, 0, 0); + minikin::MinikinFont *font = new MinikinFontSkia(skFace, NULL, 0, 0); family->addFont(font); font->Unref(); } else { @@ -78,13 +78,13 @@ static FontCollection *makeFontCollection() { } typefaces.push_back(family); - FontCollection *result = new FontCollection(typefaces); + minikin::FontCollection *result = new minikin::FontCollection(typefaces); family->Unref(); return result; } static void getDefaultTypefaceOnce() { - Layout::init(); + minikin::Layout::init(); if (gDefaultTypeface == NULL) { // We expect the client to set a default typeface, but provide a // default so we can make progress before that happens. @@ -131,16 +131,16 @@ Typeface* Typeface::createWeightAlias(Typeface* src, int weight) { return result; } -Typeface* Typeface::createFromFamilies(const std::vector<FontFamily*>& families) { +Typeface* Typeface::createFromFamilies(const std::vector<minikin::FontFamily*>& families) { Typeface* result = new Typeface; - result->fFontCollection = new FontCollection(families); + result->fFontCollection = new minikin::FontCollection(families); if (families.empty()) { ALOGW("createFromFamilies creating empty collection"); result->fSkiaStyle = SkTypeface::kNormal; } else { - const FontStyle defaultStyle; - FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]); - MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font; + const minikin::FontStyle defaultStyle; + minikin::FontFamily* firstFamily = reinterpret_cast<minikin::FontFamily*>(families[0]); + minikin::MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font; if (mf != NULL) { SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface(); // TODO: probably better to query more precise style from family, will be important diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h index 8862e5a5a911..ed0a7ebd56ae 100644 --- a/libs/hwui/hwui/Typeface.h +++ b/libs/hwui/hwui/Typeface.h @@ -27,7 +27,7 @@ namespace android { struct ANDROID_API Typeface { - FontCollection *fFontCollection; + minikin::FontCollection *fFontCollection; // style used for constructing and querying Typeface objects SkTypeface::Style fSkiaStyle; @@ -35,7 +35,7 @@ struct ANDROID_API Typeface { int fBaseWeight; // resolved style actually used for rendering - FontStyle fStyle; + minikin::FontStyle fStyle; void unref(); @@ -45,7 +45,7 @@ struct ANDROID_API Typeface { static Typeface* createWeightAlias(Typeface* src, int baseweight); - static Typeface* createFromFamilies(const std::vector<FontFamily*>& families); + static Typeface* createFromFamilies(const std::vector<minikin::FontFamily*>& families); static void setDefault(Typeface* face); }; diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp index b575c696586e..6d0293695412 100644 --- a/libs/hwui/renderstate/MeshState.cpp +++ b/libs/hwui/renderstate/MeshState.cpp @@ -17,8 +17,6 @@ #include "Program.h" -#include "ShadowTessellator.h" - namespace android { namespace uirenderer { @@ -100,6 +98,12 @@ void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, glBufferData(GL_ARRAY_BUFFER, size, data, usage); } +void MeshState::updateMeshBufferSubData(GLuint buffer, GLintptr offset, + GLsizeiptr size, const void* data) { + bindMeshBuffer(buffer); + glBufferSubData(GL_ARRAY_BUFFER, offset, size, data); +} + void MeshState::deleteMeshBuffer(GLuint buffer) { if (buffer == mCurrentBuffer) { // GL defines that deleting the currently bound VBO rebinds to 0 (no VBO). diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h index dd684686f584..17ad4622e44a 100644 --- a/libs/hwui/renderstate/MeshState.h +++ b/libs/hwui/renderstate/MeshState.h @@ -72,6 +72,7 @@ public: void unbindMeshBuffer(); void genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, const void* data, GLenum usage); + void updateMeshBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data); void deleteMeshBuffer(GLuint); /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index 5e600644ca19..ee4619d2c222 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -60,38 +60,6 @@ static void layerLostGlContext(Layer* layer) { } void RenderState::onGLContextDestroyed() { -/* - size_t size = mActiveLayers.size(); - if (CC_UNLIKELY(size != 0)) { - ALOGE("Crashing, have %d contexts and %d layers at context destruction. isempty %d", - mRegisteredContexts.size(), size, mActiveLayers.empty()); - mCaches->dumpMemoryUsage(); - for (std::set<renderthread::CanvasContext*>::iterator cit = mRegisteredContexts.begin(); - cit != mRegisteredContexts.end(); cit++) { - renderthread::CanvasContext* context = *cit; - ALOGE("Context: %p (root = %p)", context, context->mRootRenderNode.get()); - ALOGE(" Prefeteched layers: %zu", context->mPrefetechedLayers.size()); - for (std::set<RenderNode*>::iterator pit = context->mPrefetechedLayers.begin(); - pit != context->mPrefetechedLayers.end(); pit++) { - (*pit)->debugDumpLayers(" "); - } - context->mRootRenderNode->debugDumpLayers(" "); - } - - - if (mActiveLayers.begin() == mActiveLayers.end()) { - ALOGE("set has become empty. wat."); - } - for (std::set<const Layer*>::iterator lit = mActiveLayers.begin(); - lit != mActiveLayers.end(); lit++) { - const Layer* layer = *(lit); - ALOGE("Layer %p, state %d, texlayer %d, fbo %d, buildlayered %d", - layer, layer->state, layer->isTextureLayer(), layer->getFbo(), layer->wasBuildLayered); - } - LOG_ALWAYS_FATAL("%d layers have survived gl context destruction", size); - } -*/ - mLayerPool.clear(); // TODO: reset all cached state in state objects diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 5003c6aefb8b..2eccca9fee37 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -21,15 +21,16 @@ #include "Caches.h" #include "DeferredLayerUpdater.h" #include "EglManager.h" -#include "LayerUpdateQueue.h" #include "LayerRenderer.h" -#include "OpenGLRenderer.h" +#include "LayerUpdateQueue.h" #include "Properties.h" +#include "Readback.h" #include "RenderThread.h" #include "hwui/Canvas.h" #include "renderstate/RenderState.h" #include "renderstate/Stencil.h" #include "protos/hwui.pb.h" +#include "OpenGLPipeline.h" #include "utils/GLUtils.h" #include "utils/TimeUtils.h" @@ -61,15 +62,40 @@ namespace android { namespace uirenderer { namespace renderthread { +CanvasContext* CanvasContext::create(RenderThread& thread, + bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) { + + auto renderType = Properties::getRenderPipelineType(); + + switch (renderType) { + case RenderPipelineType::OpenGL: + return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, + std::make_unique<OpenGLPipeline>(thread)); + case RenderPipelineType::SkiaGL: + //TODO: implement SKIA GL + LOG_ALWAYS_FATAL("skiaGL canvas type not implemented."); + break; + case RenderPipelineType::SkiaVulkan: + //TODO: implement Vulkan + LOG_ALWAYS_FATAL("Vulkan canvas type not implemented."); + break; + default: + LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType); + break; + } + return nullptr; +} + CanvasContext::CanvasContext(RenderThread& thread, bool translucent, - RenderNode* rootRenderNode, IContextFactory* contextFactory) + RenderNode* rootRenderNode, IContextFactory* contextFactory, + std::unique_ptr<IRenderPipeline> renderPipeline) : mRenderThread(thread) - , mEglManager(thread.eglManager()) , mOpaque(!translucent) , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord())) , mJankTracker(thread.timeLord().frameIntervalNanos()) , mProfiler(mFrames) - , mContentDrawBounds(0, 0, 0, 0) { + , mContentDrawBounds(0, 0, 0, 0) + , mRenderPipeline(std::move(renderPipeline)) { mRenderNodes.emplace_back(rootRenderNode); mRenderThread.renderState().registerCanvasContext(this); mProfiler.setDensity(mRenderThread.mainDisplayInfo().density); @@ -86,12 +112,6 @@ void CanvasContext::destroy(TreeObserver* observer) { freePrefetchedLayers(observer); destroyHardwareResources(observer); mAnimationContext->destroy(); -#if !HWUI_NEW_OPS - if (mCanvas) { - delete mCanvas; - mCanvas = nullptr; - } -#endif } void CanvasContext::setSurface(Surface* surface) { @@ -99,24 +119,15 @@ void CanvasContext::setSurface(Surface* surface) { mNativeSurface = surface; - if (mEglSurface != EGL_NO_SURFACE) { - mEglManager.destroySurface(mEglSurface); - mEglSurface = EGL_NO_SURFACE; - } - - if (surface) { - mEglSurface = mEglManager.createSurface(surface); - } + bool hasSurface = mRenderPipeline->setSurface(surface, mSwapBehavior); mFrameNumber = -1; - if (mEglSurface != EGL_NO_SURFACE) { - const bool preserveBuffer = (mSwapBehavior != kSwap_discardBuffer); - mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); - mHaveNewSurface = true; - mSwapHistory.clear(); + if (hasSurface) { + mHaveNewSurface = true; + mSwapHistory.clear(); } else { - mRenderThread.removeFrameCallback(this); + mRenderThread.removeFrameCallback(this); } } @@ -126,11 +137,6 @@ void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) { void CanvasContext::initialize(Surface* surface) { setSurface(surface); -#if !HWUI_NEW_OPS - if (mCanvas) return; - mCanvas = new OpenGLRenderer(mRenderThread.renderState()); - mCanvas->initProperties(); -#endif } void CanvasContext::updateSurface(Surface* surface) { @@ -146,35 +152,22 @@ void CanvasContext::setStopped(bool stopped) { mStopped = stopped; if (mStopped) { mRenderThread.removeFrameCallback(this); - if (mEglManager.isCurrent(mEglSurface)) { - mEglManager.makeCurrent(EGL_NO_SURFACE); - } + mRenderPipeline->onStop(); } else if (mIsDirty && hasSurface()) { mRenderThread.postFrameCallback(this); } } } -// TODO: don't pass viewport size, it's automatic via EGL -void CanvasContext::setup(int width, int height, float lightRadius, +void CanvasContext::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { -#if HWUI_NEW_OPS mLightGeometry.radius = lightRadius; mLightInfo.ambientShadowAlpha = ambientShadowAlpha; mLightInfo.spotShadowAlpha = spotShadowAlpha; -#else - if (!mCanvas) return; - mCanvas->initLight(lightRadius, ambientShadowAlpha, spotShadowAlpha); -#endif } void CanvasContext::setLightCenter(const Vector3& lightCenter) { -#if HWUI_NEW_OPS mLightGeometry.center = lightCenter; -#else - if (!mCanvas) return; - mCanvas->setLightCenter(lightCenter); -#endif } void CanvasContext::setOpaque(bool opaque) { @@ -184,14 +177,23 @@ void CanvasContext::setOpaque(bool opaque) { bool CanvasContext::makeCurrent() { if (mStopped) return false; - // TODO: Figure out why this workaround is needed, see b/13913604 - // In the meantime this matches the behavior of GLRenderer, so it is not a regression - EGLint error = 0; - mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface, &error); - if (error) { - setSurface(nullptr); + auto result = mRenderPipeline->makeCurrent(); + switch (result) { + case MakeCurrentResult::AlreadyCurrent: + return true; + case MakeCurrentResult::Failed: + mHaveNewSurface = true; + setSurface(nullptr); + return false; + case MakeCurrentResult::Succeeded: + mHaveNewSurface = true; + return true; + default: + LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent", + (int32_t) result); } - return !error; + + return true; } static bool wasSkipped(FrameInfo* info) { @@ -251,11 +253,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, mCurrentFrameInfo->markSyncStart(); info.damageAccumulator = &mDamageAccumulator; -#if HWUI_NEW_OPS info.layerUpdateQueue = &mLayerUpdateQueue; -#else - info.renderer = mCanvas; -#endif mAnimationContext->startFrame(info.mode); for (const sp<RenderNode>& node : mRenderNodes) { @@ -280,7 +278,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, return; } - if (CC_LIKELY(mSwapHistory.size())) { + if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) { nsecs_t latestVsync = mRenderThread.timeLord().latestVsync(); SwapHistory& lastSwap = mSwapHistory.back(); int durationUs; @@ -332,11 +330,6 @@ void CanvasContext::notifyFramePending() { } void CanvasContext::draw() { -#if !HWUI_NEW_OPS - LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, - "drawRenderNode called on a context with no canvas or surface!"); -#endif - SkRect dirty; mDamageAccumulator.finish(&dirty); @@ -348,215 +341,27 @@ void CanvasContext::draw() { mCurrentFrameInfo->markIssueDrawCommandsStart(); - Frame frame = mEglManager.beginFrame(mEglSurface); - - if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) { - // can't rely on prior content of window if viewport size changes - dirty.setEmpty(); - mLastFrameWidth = frame.width(); - mLastFrameHeight = frame.height(); - } else if (mHaveNewSurface || frame.bufferAge() == 0) { - // New surface needs a full draw - dirty.setEmpty(); - } else { - if (!dirty.isEmpty() && !dirty.intersect(0, 0, frame.width(), frame.height())) { - ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", - SK_RECT_ARGS(dirty), frame.width(), frame.height()); - dirty.setEmpty(); - } - profiler().unionDirty(&dirty); - } - - if (dirty.isEmpty()) { - dirty.set(0, 0, frame.width(), frame.height()); - } - - // At this point dirty is the area of the screen to update. However, - // the area of the frame we need to repaint is potentially different, so - // stash the screen area for later - SkRect screenDirty(dirty); - - // If the buffer age is 0 we do a full-screen repaint (handled above) - // If the buffer age is 1 the buffer contents are the same as they were - // last frame so there's nothing to union() against - // Therefore we only care about the > 1 case. - if (frame.bufferAge() > 1) { - if (frame.bufferAge() > (int) mSwapHistory.size()) { - // We don't have enough history to handle this old of a buffer - // Just do a full-draw - dirty.set(0, 0, frame.width(), frame.height()); - } else { - // At this point we haven't yet added the latest frame - // to the damage history (happens below) - // So we need to damage - for (int i = mSwapHistory.size() - 1; - i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) { - dirty.join(mSwapHistory[i].damage); - } - } - } - - mEglManager.damageFrame(frame, dirty); - -#if HWUI_NEW_OPS - auto& caches = Caches::getInstance(); - FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), mLightGeometry, caches); + Frame frame = mRenderPipeline->getFrame(); - frameBuilder.deferLayers(mLayerUpdateQueue); - mLayerUpdateQueue.clear(); + SkRect windowDirty = computeDirtyRect(frame, &dirty); - frameBuilder.deferRenderNodeScene(mRenderNodes, mContentDrawBounds); - - BakedOpRenderer renderer(caches, mRenderThread.renderState(), - mOpaque, mLightInfo); - frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); - profiler().draw(&renderer); - bool drew = renderer.didDraw(); - - // post frame cleanup - caches.clearGarbage(); - caches.pathCache.trim(); - caches.tessellationCache.trim(); - -#if DEBUG_MEMORY_USAGE - mCaches.dumpMemoryUsage(); -#else - if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) { - caches.dumpMemoryUsage(); - } -#endif - -#else - mCanvas->prepareDirty(frame.width(), frame.height(), - dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque); - - Rect outBounds; - // It there are multiple render nodes, they are laid out as follows: - // #0 - backdrop (content + caption) - // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds) - // #2 - additional overlay nodes - // Usually the backdrop cannot be seen since it will be entirely covered by the content. While - // resizing however it might become partially visible. The following render loop will crop the - // backdrop against the content and draw the remaining part of it. It will then draw the content - // cropped to the backdrop (since that indicates a shrinking of the window). - // - // Additional nodes will be drawn on top with no particular clipping semantics. - - // The bounds of the backdrop against which the content should be clipped. - Rect backdropBounds = mContentDrawBounds; - // Usually the contents bounds should be mContentDrawBounds - however - we will - // move it towards the fixed edge to give it a more stable appearance (for the moment). - Rect contentBounds; - // If there is no content bounds we ignore the layering as stated above and start with 2. - int layer = (mContentDrawBounds.isEmpty() || mRenderNodes.size() == 1) ? 2 : 0; - // Draw all render nodes. Note that - for (const sp<RenderNode>& node : mRenderNodes) { - if (layer == 0) { // Backdrop. - // Draw the backdrop clipped to the inverse content bounds, but assume that the content - // was moved to the upper left corner. - const RenderProperties& properties = node->properties(); - Rect targetBounds(properties.getLeft(), properties.getTop(), - properties.getRight(), properties.getBottom()); - // Move the content bounds towards the fixed corner of the backdrop. - const int x = targetBounds.left; - const int y = targetBounds.top; - contentBounds.set(x, y, x + mContentDrawBounds.getWidth(), - y + mContentDrawBounds.getHeight()); - // Remember the intersection of the target bounds and the intersection bounds against - // which we have to crop the content. - backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight()); - backdropBounds.doIntersect(targetBounds); - // Check if we have to draw something on the left side ... - if (targetBounds.left < contentBounds.left) { - mCanvas->save(SaveFlags::Clip); - if (mCanvas->clipRect(targetBounds.left, targetBounds.top, - contentBounds.left, targetBounds.bottom, - SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - // Reduce the target area by the area we have just painted. - targetBounds.left = std::min(contentBounds.left, targetBounds.right); - mCanvas->restore(); - } - // ... or on the right side ... - if (targetBounds.right > contentBounds.right && - !targetBounds.isEmpty()) { - mCanvas->save(SaveFlags::Clip); - if (mCanvas->clipRect(contentBounds.right, targetBounds.top, - targetBounds.right, targetBounds.bottom, - SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - // Reduce the target area by the area we have just painted. - targetBounds.right = std::max(targetBounds.left, contentBounds.right); - mCanvas->restore(); - } - // ... or at the top ... - if (targetBounds.top < contentBounds.top && - !targetBounds.isEmpty()) { - mCanvas->save(SaveFlags::Clip); - if (mCanvas->clipRect(targetBounds.left, targetBounds.top, targetBounds.right, - contentBounds.top, - SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - // Reduce the target area by the area we have just painted. - targetBounds.top = std::min(contentBounds.top, targetBounds.bottom); - mCanvas->restore(); - } - // ... or at the bottom. - if (targetBounds.bottom > contentBounds.bottom && - !targetBounds.isEmpty()) { - mCanvas->save(SaveFlags::Clip); - if (mCanvas->clipRect(targetBounds.left, contentBounds.bottom, targetBounds.right, - targetBounds.bottom, SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - mCanvas->restore(); - } - } else if (layer == 1) { // Content - // It gets cropped against the bounds of the backdrop to stay inside. - mCanvas->save(SaveFlags::MatrixClip); - - // We shift and clip the content to match its final location in the window. - const float left = mContentDrawBounds.left; - const float top = mContentDrawBounds.top; - const float dx = backdropBounds.left - left; - const float dy = backdropBounds.top - top; - const float width = backdropBounds.getWidth(); - const float height = backdropBounds.getHeight(); - - mCanvas->translate(dx, dy); - if (mCanvas->clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - mCanvas->restore(); - } else { // draw the rest on top at will! - mCanvas->drawRenderNode(node.get(), outBounds); - } - layer++; - } - - profiler().draw(mCanvas); - - bool drew = mCanvas->finish(); -#endif + bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, + mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler())); waitOnFences(); - GL_CHECKPOINT(LOW); + bool requireSwap = false; + bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, + &requireSwap); - // Even if we decided to cancel the frame, from the perspective of jank - // metrics the frame was swapped at this point - mCurrentFrameInfo->markSwapBuffers(); mIsDirty = false; - if (drew || mEglManager.damageRequiresSwap()) { - if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) { + if (requireSwap) { + if (!didSwap) { //some error happened setSurface(nullptr); } SwapHistory& swap = mSwapHistory.next(); - swap.damage = screenDirty; + swap.damage = windowDirty; swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC); swap.vsyncTime = mRenderThread.timeLord().latestVsync(); mHaveNewSurface = false; @@ -592,11 +397,7 @@ void CanvasContext::draw() { // Called by choreographer to do an RT-driven animation void CanvasContext::doFrame() { -#if HWUI_NEW_OPS - if (CC_UNLIKELY(mEglSurface == EGL_NO_SURFACE)) return; -#else - if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) return; -#endif + if (!mRenderPipeline->isSurfaceReady()) return; prepareAndDraw(nullptr); } @@ -646,10 +447,7 @@ void CanvasContext::freePrefetchedLayers(TreeObserver* observer) { void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) { ATRACE_CALL(); - if (!mEglManager.hasEglContext()) return; -#if !HWUI_NEW_OPS - if (!mCanvas) return; -#endif + if (!mRenderPipeline->isContextReady()) return; // buildLayer() will leave the tree in an unknown state, so we must stop drawing stopDrawing(); @@ -657,11 +455,7 @@ void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) { TreeInfo info(TreeInfo::MODE_FULL, *this); info.damageAccumulator = &mDamageAccumulator; info.observer = observer; -#if HWUI_NEW_OPS info.layerUpdateQueue = &mLayerUpdateQueue; -#else - info.renderer = mCanvas; -#endif info.runAnimations = false; node->prepareTree(info); SkRect ignore; @@ -670,41 +464,24 @@ void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) { // purposes when the frame is actually drawn node->setPropertyFieldsDirty(RenderNode::GENERIC); -#if HWUI_NEW_OPS - static const std::vector< sp<RenderNode> > emptyNodeList; - auto& caches = Caches::getInstance(); - FrameBuilder frameBuilder(mLayerUpdateQueue, mLightGeometry, caches); - mLayerUpdateQueue.clear(); - BakedOpRenderer renderer(caches, mRenderThread.renderState(), - mOpaque, mLightInfo); - LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case"); - frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); -#else - mCanvas->markLayersAsBuildLayers(); - mCanvas->flushLayerUpdates(); -#endif + mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo); node->incStrong(nullptr); mPrefetchedLayers.insert(node); } bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { - layer->apply(); - return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap); + return mRenderPipeline->copyLayerInto(layer, bitmap); } void CanvasContext::destroyHardwareResources(TreeObserver* observer) { stopDrawing(); - if (mEglManager.hasEglContext()) { + if (mRenderPipeline->isContextReady()) { freePrefetchedLayers(observer); for (const sp<RenderNode>& node : mRenderNodes) { node->destroyHardwareResources(observer); } - Caches& caches = Caches::getInstance(); - // Make sure to release all the textures we were owning as there won't - // be another draw - caches.textureCache.resetMarkInUse(this); - mRenderThread.renderState().flush(Caches::FlushMode::Layers); + mRenderPipeline->onDestroyHardwareResources(); } } @@ -721,15 +498,8 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) { } } -void CanvasContext::runWithGlContext(RenderTask* task) { - LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), - "GL context not initialized!"); - task->run(); -} - Layer* CanvasContext::createTextureLayer() { - mEglManager.initialize(); - return LayerRenderer::createTextureLayer(mRenderThread.renderState()); + return mRenderPipeline->createTextureLayer(); } void CanvasContext::setTextureAtlas(RenderThread& thread, @@ -809,8 +579,8 @@ void CanvasContext::waitOnFences() { class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> { public: - FuncTaskProcessor(Caches& caches) - : TaskProcessor<bool>(&caches.tasks) {} + explicit FuncTaskProcessor(TaskManager* taskManager) + : TaskProcessor<bool>(taskManager) {} virtual void onProcess(const sp<Task<bool> >& task) override { FuncTask* t = static_cast<FuncTask*>(task.get()); @@ -821,7 +591,7 @@ public: void CanvasContext::enqueueFrameWork(std::function<void()>&& func) { if (!mFrameWorkProcessor.get()) { - mFrameWorkProcessor = new FuncTaskProcessor(Caches::getInstance()); + mFrameWorkProcessor = new FuncTaskProcessor(mRenderPipeline->getTaskManager()); } sp<FuncTask> task(new FuncTask()); task->func = func; @@ -837,6 +607,56 @@ int64_t CanvasContext::getFrameNumber() { return mFrameNumber; } +SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { + if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) { + // can't rely on prior content of window if viewport size changes + dirty->setEmpty(); + mLastFrameWidth = frame.width(); + mLastFrameHeight = frame.height(); + } else if (mHaveNewSurface || frame.bufferAge() == 0) { + // New surface needs a full draw + dirty->setEmpty(); + } else { + if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) { + ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", + SK_RECT_ARGS(*dirty), frame.width(), frame.height()); + dirty->setEmpty(); + } + profiler().unionDirty(dirty); + } + + if (dirty->isEmpty()) { + dirty->set(0, 0, frame.width(), frame.height()); + } + + // At this point dirty is the area of the window to update. However, + // the area of the frame we need to repaint is potentially different, so + // stash the screen area for later + SkRect windowDirty(*dirty); + + // If the buffer age is 0 we do a full-screen repaint (handled above) + // If the buffer age is 1 the buffer contents are the same as they were + // last frame so there's nothing to union() against + // Therefore we only care about the > 1 case. + if (frame.bufferAge() > 1) { + if (frame.bufferAge() > (int) mSwapHistory.size()) { + // We don't have enough history to handle this old of a buffer + // Just do a full-draw + dirty->set(0, 0, frame.width(), frame.height()); + } else { + // At this point we haven't yet added the latest frame + // to the damage history (happens below) + // So we need to damage + for (int i = mSwapHistory.size() - 1; + i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) { + dirty->join(mSwapHistory[i].damage); + } + } + } + + return windowDirty; +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index b0d980b94308..42e9be33d4ea 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -14,14 +14,17 @@ * limitations under the License. */ -#ifndef CANVASCONTEXT_H_ -#define CANVASCONTEXT_H_ +#pragma once +#include "BakedOpDispatcher.h" +#include "BakedOpRenderer.h" #include "DamageAccumulator.h" +#include "FrameBuilder.h" #include "FrameInfo.h" #include "FrameInfoVisualizer.h" #include "FrameMetricsReporter.h" #include "IContextFactory.h" +#include "IRenderPipeline.h" #include "LayerUpdateQueue.h" #include "RenderNode.h" #include "thread/Task.h" @@ -30,12 +33,6 @@ #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" -#if HWUI_NEW_OPS -#include "BakedOpDispatcher.h" -#include "BakedOpRenderer.h" -#include "FrameBuilder.h" -#endif - #include <cutils/compiler.h> #include <EGL/egl.h> #include <SkBitmap.h> @@ -53,27 +50,22 @@ namespace uirenderer { class AnimationContext; class DeferredLayerUpdater; -class OpenGLRenderer; -class Rect; class Layer; +class Rect; class RenderState; namespace renderthread { class EglManager; - -enum SwapBehavior { - kSwap_default, - kSwap_discardBuffer, -}; +class Frame; // This per-renderer class manages the bridge between the global EGL context // and the render surface. // TODO: Rename to Renderer or some other per-window, top-level manager class CanvasContext : public IFrameCallback { public: - CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, - IContextFactory* contextFactory); + static CanvasContext* create(RenderThread& thread, bool translucent, + RenderNode* rootRenderNode, IContextFactory* contextFactory); virtual ~CanvasContext(); // Won't take effect until next EGLSurface creation @@ -85,7 +77,7 @@ public: void setStopped(bool stopped); bool hasSurface() { return mNativeSurface.get(); } - void setup(int width, int height, float lightRadius, + void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); void setLightCenter(const Vector3& lightCenter); void setOpaque(bool opaque); @@ -108,8 +100,6 @@ public: static void invokeFunctor(RenderThread& thread, Functor* functor); - void runWithGlContext(RenderTask* task); - Layer* createTextureLayer(); ANDROID_API static void setTextureAtlas(RenderThread& thread, @@ -169,6 +159,9 @@ public: ANDROID_API int64_t getFrameNumber(); private: + CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, + IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline); + friend class RegisterFrameCallbackTask; // TODO: Replace with something better for layer & other GL object // lifecycle tracking @@ -182,21 +175,20 @@ private: bool isSwapChainStuffed(); + SkRect computeDirtyRect(const Frame& frame, SkRect* dirty); + EGLint mLastFrameWidth = 0; EGLint mLastFrameHeight = 0; RenderThread& mRenderThread; - EglManager& mEglManager; sp<Surface> mNativeSurface; - EGLSurface mEglSurface = EGL_NO_SURFACE; // stopped indicates the CanvasContext will reject actual redraw operations, // and defer repaint until it is un-stopped bool mStopped = false; // CanvasContext is dirty if it has received an update that it has not // painted onto its surface. bool mIsDirty = false; - bool mBufferPreserved = false; - SwapBehavior mSwapBehavior = kSwap_default; + SwapBehavior mSwapBehavior = SwapBehavior::kSwap_default; struct SwapHistory { SkRect damage; nsecs_t vsyncTime; @@ -209,12 +201,8 @@ private: int64_t mFrameNumber = -1; bool mOpaque; -#if HWUI_NEW_OPS BakedOpRenderer::LightInfo mLightInfo; FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 }; -#else - OpenGLRenderer* mCanvas = nullptr; -#endif bool mHaveNewSurface = false; DamageAccumulator mDamageAccumulator; @@ -245,9 +233,9 @@ private: std::vector< sp<FuncTask> > mFrameFences; sp<TaskProcessor<bool> > mFrameWorkProcessor; + std::unique_ptr<IRenderPipeline> mRenderPipeline; }; } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ -#endif /* CANVASCONTEXT_H_ */ diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h new file mode 100644 index 000000000000..0c0fbe9d716c --- /dev/null +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "FrameInfoVisualizer.h" +#include "EglManager.h" + +#include <SkRect.h> +#include <utils/RefBase.h> + +namespace android { + +class Surface; + +namespace uirenderer { + +class DeferredLayerUpdater; + +namespace renderthread { + +enum class SwapBehavior { + kSwap_default, + kSwap_discardBuffer, +}; + +enum class MakeCurrentResult { + AlreadyCurrent, + Failed, + Succeeded +}; + +class IRenderPipeline { +public: + virtual MakeCurrentResult makeCurrent() = 0; + virtual Frame getFrame() = 0; + virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, + const FrameBuilder::LightGeometry& lightGeometry, + LayerUpdateQueue* layerUpdateQueue, + const Rect& contentDrawBounds, bool opaque, + const BakedOpRenderer::LightInfo& lightInfo, + const std::vector< sp<RenderNode> >& renderNodes, + FrameInfoVisualizer* profiler) = 0; + virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, + FrameInfo* currentFrameInfo, bool* requireSwap) = 0; + virtual bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) = 0; + virtual Layer* createTextureLayer() = 0; + virtual bool setSurface(Surface* window, SwapBehavior swapBehavior) = 0; + virtual void onStop() = 0; + virtual bool isSurfaceReady() = 0; + virtual bool isContextReady() = 0; + virtual void onDestroyHardwareResources() = 0; + virtual void renderLayers(const FrameBuilder::LightGeometry& lightGeometry, + LayerUpdateQueue* layerUpdateQueue, bool opaque, + const BakedOpRenderer::LightInfo& lightInfo) = 0; + virtual TaskManager* getTaskManager() = 0; + + virtual ~IRenderPipeline() {} +}; + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp new file mode 100644 index 000000000000..3a2b15584d50 --- /dev/null +++ b/libs/hwui/renderthread/OpenGLPipeline.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OpenGLPipeline.h" + +#include "DeferredLayerUpdater.h" +#include "EglManager.h" +#include "LayerRenderer.h" +#include "renderstate/RenderState.h" +#include "Readback.h" + +#include <android/native_window.h> +#include <cutils/properties.h> +#include <strings.h> + +namespace android { +namespace uirenderer { +namespace renderthread { + +OpenGLPipeline::OpenGLPipeline(RenderThread& thread) + : mEglManager(thread.eglManager()), mRenderThread(thread) { +} + +MakeCurrentResult OpenGLPipeline::makeCurrent() { + // TODO: Figure out why this workaround is needed, see b/13913604 + // In the meantime this matches the behavior of GLRenderer, so it is not a regression + EGLint error = 0; + bool haveNewSurface = mEglManager.makeCurrent(mEglSurface, &error); + + Caches::getInstance().textureCache.resetMarkInUse(this); + if (!haveNewSurface) { + return MakeCurrentResult::AlreadyCurrent; + } + return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded; +} + +Frame OpenGLPipeline::getFrame() { + LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE, + "drawRenderNode called on a context with no surface!"); + return mEglManager.beginFrame(mEglSurface); +} + +bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, + const FrameBuilder::LightGeometry& lightGeometry, + LayerUpdateQueue* layerUpdateQueue, + const Rect& contentDrawBounds, bool opaque, + const BakedOpRenderer::LightInfo& lightInfo, + const std::vector< sp<RenderNode> >& renderNodes, + FrameInfoVisualizer* profiler) { + + mEglManager.damageFrame(frame, dirty); + + bool drew = false; + + + auto& caches = Caches::getInstance(); + FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches); + + frameBuilder.deferLayers(*layerUpdateQueue); + layerUpdateQueue->clear(); + + frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds); + + BakedOpRenderer renderer(caches, mRenderThread.renderState(), + opaque, lightInfo); + frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); + profiler->draw(&renderer); + drew = renderer.didDraw(); + + // post frame cleanup + caches.clearGarbage(); + caches.pathCache.trim(); + caches.tessellationCache.trim(); + +#if DEBUG_MEMORY_USAGE + mCaches.dumpMemoryUsage(); +#else + if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) { + caches.dumpMemoryUsage(); + } +#endif + + return drew; +} + +bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, + FrameInfo* currentFrameInfo, bool* requireSwap) { + + GL_CHECKPOINT(LOW); + + // Even if we decided to cancel the frame, from the perspective of jank + // metrics the frame was swapped at this point + currentFrameInfo->markSwapBuffers(); + + *requireSwap = drew || mEglManager.damageRequiresSwap(); + + if (*requireSwap && (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty)))) { + return false; + } + + return *requireSwap; +} + +bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { + layer->apply(); + return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap) + == CopyResult::Success; +} + +Layer* OpenGLPipeline::createTextureLayer() { + mEglManager.initialize(); + return LayerRenderer::createTextureLayer(mRenderThread.renderState()); +} + +void OpenGLPipeline::onStop() { + if (mEglManager.isCurrent(mEglSurface)) { + mEglManager.makeCurrent(EGL_NO_SURFACE); + } +} + +bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) { + + if (mEglSurface != EGL_NO_SURFACE) { + mEglManager.destroySurface(mEglSurface); + mEglSurface = EGL_NO_SURFACE; + } + + if (surface) { + mEglSurface = mEglManager.createSurface(surface); + } + + if (mEglSurface != EGL_NO_SURFACE) { + const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer); + mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); + return true; + } + + return false; +} + +bool OpenGLPipeline::isSurfaceReady() { + return CC_UNLIKELY(mEglSurface != EGL_NO_SURFACE); +} + +bool OpenGLPipeline::isContextReady() { + return CC_LIKELY(mEglManager.hasEglContext()); +} + +void OpenGLPipeline::onDestroyHardwareResources() { + Caches& caches = Caches::getInstance(); + // Make sure to release all the textures we were owning as there won't + // be another draw + caches.textureCache.resetMarkInUse(this); + mRenderThread.renderState().flush(Caches::FlushMode::Layers); +} + +void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry, + LayerUpdateQueue* layerUpdateQueue, bool opaque, + const BakedOpRenderer::LightInfo& lightInfo) { + static const std::vector< sp<RenderNode> > emptyNodeList; + auto& caches = Caches::getInstance(); + FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches); + layerUpdateQueue->clear(); + BakedOpRenderer renderer(caches, mRenderThread.renderState(), + opaque, lightInfo); + LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case"); + frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); +} + +TaskManager* OpenGLPipeline::getTaskManager() { + return &Caches::getInstance().tasks; +} + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h new file mode 100644 index 000000000000..a6d22ee8b34f --- /dev/null +++ b/libs/hwui/renderthread/OpenGLPipeline.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "CanvasContext.h" +#include "BakedOpDispatcher.h" +#include "BakedOpRenderer.h" +#include "FrameBuilder.h" +#include "IRenderPipeline.h" + +namespace android { +namespace uirenderer { +namespace renderthread { + +class Frame; + + +class OpenGLPipeline : public IRenderPipeline { +public: + OpenGLPipeline(RenderThread& thread); + virtual ~OpenGLPipeline() {} + + MakeCurrentResult makeCurrent() override; + Frame getFrame() override; + bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, + const FrameBuilder::LightGeometry& lightGeometry, + LayerUpdateQueue* layerUpdateQueue, + const Rect& contentDrawBounds, bool opaque, + const BakedOpRenderer::LightInfo& lightInfo, + const std::vector< sp<RenderNode> >& renderNodes, + FrameInfoVisualizer* profiler) override; + bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, + FrameInfo* currentFrameInfo, bool* requireSwap) override; + bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override; + Layer* createTextureLayer() override; + bool setSurface(Surface* window, SwapBehavior swapBehavior) override; + void onStop() override; + bool isSurfaceReady() override; + bool isContextReady() override; + void onDestroyHardwareResources() override; + void renderLayers(const FrameBuilder::LightGeometry& lightGeometry, + LayerUpdateQueue* layerUpdateQueue, bool opaque, + const BakedOpRenderer::LightInfo& lightInfo) override; + TaskManager* getTaskManager() override; + +private: + EglManager& mEglManager; + EGLSurface mEglSurface = EGL_NO_SURFACE; + bool mBufferPreserved = false; + RenderThread& mRenderThread; +}; + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 06a24b248bf6..d860acd1edd1 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -55,7 +55,7 @@ namespace renderthread { CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) { - return new CanvasContext(*args->thread, args->translucent, + return CanvasContext::create(*args->thread, args->translucent, args->rootRenderNode, args->contextFactory); } @@ -180,19 +180,17 @@ void RenderProxy::setStopped(bool stopped) { postAndWait(task); } -CREATE_BRIDGE6(setup, CanvasContext* context, int width, int height, +CREATE_BRIDGE4(setup, CanvasContext* context, float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { - args->context->setup(args->width, args->height, args->lightRadius, + args->context->setup(args->lightRadius, args->ambientShadowAlpha, args->spotShadowAlpha); return nullptr; } -void RenderProxy::setup(int width, int height, float lightRadius, +void RenderProxy::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { SETUP_TASK(setup); args->context = mContext; - args->width = width; - args->height = height; args->lightRadius = lightRadius; args->ambientShadowAlpha = ambientShadowAlpha; args->spotShadowAlpha = spotShadowAlpha; @@ -267,18 +265,6 @@ void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) { } } -CREATE_BRIDGE2(runWithGlContext, CanvasContext* context, RenderTask* task) { - args->context->runWithGlContext(args->task); - return nullptr; -} - -void RenderProxy::runWithGlContext(RenderTask* gltask) { - SETUP_TASK(runWithGlContext); - args->context = mContext; - args->task = gltask; - postAndWait(task); -} - CREATE_BRIDGE1(createTextureLayer, CanvasContext* context) { Layer* layer = args->context->createTextureLayer(); if (!layer) return nullptr; @@ -456,6 +442,19 @@ void RenderProxy::resetProfileInfo() { postAndWait(task); } +CREATE_BRIDGE2(frameTimePercentile, RenderThread* thread, int percentile) { + return reinterpret_cast<void*>(static_cast<uintptr_t>( + args->thread->jankTracker().findPercentile(args->percentile))); +} + +uint32_t RenderProxy::frameTimePercentile(int p) { + SETUP_TASK(frameTimePercentile); + args->thread = &mRenderThread; + args->percentile = p; + return static_cast<uint32_t>(reinterpret_cast<uintptr_t>( + postAndWait(task))); +} + CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) { args->thread->jankTracker().dump(args->fd); @@ -467,11 +466,7 @@ CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) { } else { fprintf(file, "\nNo caches instance.\n"); } -#if HWUI_NEW_OPS fprintf(file, "\nPipeline=FrameBuilder\n"); -#else - fprintf(file, "\nPipeline=OpenGLRenderer\n"); -#endif fflush(file); return nullptr; } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index e31062c83734..0bee858a84fa 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -80,7 +80,7 @@ public: ANDROID_API void updateSurface(const sp<Surface>& surface); ANDROID_API bool pauseSurface(const sp<Surface>& surface); ANDROID_API void setStopped(bool stopped); - ANDROID_API void setup(int width, int height, float lightRadius, + ANDROID_API void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha); ANDROID_API void setLightCenter(const Vector3& lightCenter); ANDROID_API void setOpaque(bool opaque); @@ -90,8 +90,6 @@ public: ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion); - ANDROID_API void runWithGlContext(RenderTask* task); - ANDROID_API DeferredLayerUpdater* createTextureLayer(); ANDROID_API void buildLayer(RenderNode* node, TreeObserver* observer); ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap); @@ -111,6 +109,7 @@ public: ANDROID_API void dumpProfileInfo(int fd, int dumpFlags); // Not exported, only used for testing void resetProfileInfo(); + uint32_t frameTimePercentile(int p); ANDROID_API static void dumpGraphicsMemory(int fd); ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size); diff --git a/libs/hwui/tests/common/LeakChecker.cpp b/libs/hwui/tests/common/LeakChecker.cpp new file mode 100644 index 000000000000..d935382cc9a4 --- /dev/null +++ b/libs/hwui/tests/common/LeakChecker.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LeakChecker.h" + +#include "Caches.h" +#include "TestUtils.h" + +#include <cstdio> +#include <iostream> +#include <memunreachable/memunreachable.h> +#include <unistd.h> +#include <unordered_set> + +using namespace std; + +namespace android { +namespace uirenderer { +namespace test { + +static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) { + // merge them all + UnreachableMemoryInfo merged; + unordered_set<uintptr_t> addrs; + merged.allocation_bytes = 0; + merged.leak_bytes = 0; + merged.num_allocations = 0; + merged.num_leaks = 0; + for (auto& info : infolist) { + // We'll be a little hazzy about these ones and just hope the biggest + // is the most accurate + merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes); + merged.num_allocations = max(merged.num_allocations, info.num_allocations); + for (auto& leak : info.leaks) { + if (addrs.find(leak.begin) == addrs.end()) { + merged.leaks.push_back(leak); + merged.num_leaks++; + merged.leak_bytes += leak.size; + addrs.insert(leak.begin); + } + } + } + + // Now log the result + if (merged.num_leaks) { + cout << endl << "Leaked memory!" << endl; + if (!merged.leaks[0].backtrace.num_frames) { + cout << "Re-run with 'setprop libc.debug.malloc.program hwui_unit_test'" + << endl << "and 'setprop libc.debug.malloc.options backtrace=8'" + << " to get backtraces" << endl; + } + cout << merged.ToString(false); + } +} + +void LeakChecker::checkForLeaks() { + // TODO: Until we can shutdown the RT thread we need to do this in + // two passes as GetUnreachableMemory has limited insight into + // thread-local caches so some leaks will not be properly tagged as leaks + UnreachableMemoryInfo rtMemInfo; + TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) { + if (Caches::hasInstance()) { + Caches::getInstance().tasks.stop(); + } + // Check for leaks + if (!GetUnreachableMemory(rtMemInfo)) { + cerr << "Failed to get unreachable memory!" << endl; + return; + } + }); + UnreachableMemoryInfo uiMemInfo; + if (!GetUnreachableMemory(uiMemInfo)) { + cerr << "Failed to get unreachable memory!" << endl; + return; + } + logUnreachable({rtMemInfo, uiMemInfo}); +} + +} /* namespace test */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/tests/common/LeakChecker.h b/libs/hwui/tests/common/LeakChecker.h new file mode 100644 index 000000000000..cdf47d6bda80 --- /dev/null +++ b/libs/hwui/tests/common/LeakChecker.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +namespace android { +namespace uirenderer { +namespace test { + +class LeakChecker { +public: + static void checkForLeaks(); +}; // class TestUtils + +} /* namespace test */ +} /* namespace uirenderer */ +} /* namespace android */
\ No newline at end of file diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp index 146e735839d1..1c7e7eef7626 100644 --- a/libs/hwui/tests/common/TestContext.cpp +++ b/libs/hwui/tests/common/TestContext.cpp @@ -62,20 +62,53 @@ TestContext::TestContext() { TestContext::~TestContext() {} sp<Surface> TestContext::surface() { - if (!mSurfaceControl.get()) { - mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"), - gDisplay.w, gDisplay.h, PIXEL_FORMAT_RGBX_8888); - - SurfaceComposerClient::openGlobalTransaction(); - mSurfaceControl->setLayer(0x7FFFFFF); - mSurfaceControl->show(); - SurfaceComposerClient::closeGlobalTransaction(); + if (!mSurface.get()) { + createSurface(); } + return mSurface; +} + +void TestContext::createSurface() { + if (mRenderOffscreen) { + createOffscreenSurface(); + } else { + createWindowSurface(); + } +} - return mSurfaceControl->getSurface(); +void TestContext::createWindowSurface() { + mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"), + gDisplay.w, gDisplay.h, PIXEL_FORMAT_RGBX_8888); + + SurfaceComposerClient::openGlobalTransaction(); + mSurfaceControl->setLayer(0x7FFFFFF); + mSurfaceControl->show(); + SurfaceComposerClient::closeGlobalTransaction(); + mSurface = mSurfaceControl->getSurface(); +} + +void TestContext::createOffscreenSurface() { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + producer->setMaxDequeuedBufferCount(3); + producer->setAsyncMode(true); + mConsumer = new BufferItemConsumer(consumer, GRALLOC_USAGE_HW_COMPOSER, 4); + mConsumer->setDefaultBufferSize(gDisplay.w, gDisplay.h); + mSurface = new Surface(producer); } void TestContext::waitForVsync() { + if (mConsumer.get()) { + BufferItem buffer; + if (mConsumer->acquireBuffer(&buffer, 0, false) == OK) { + // We assume the producer is internally ordered enough such that + // it is unneccessary to set a release fence + mConsumer->releaseBuffer(buffer); + } + // We running free, go go go! + return; + } #if !HWUI_NULL_GPU // Request vsync mDisplayEventReceiver.requestNextVsync(); diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h index 2bbe5dffd9b8..312988b968de 100644 --- a/libs/hwui/tests/common/TestContext.h +++ b/libs/hwui/tests/common/TestContext.h @@ -19,12 +19,16 @@ #include <gui/DisplayEventReceiver.h> #include <gui/ISurfaceComposer.h> +#include <gui/BufferItemConsumer.h> #include <gui/SurfaceComposerClient.h> #include <gui/SurfaceControl.h> #include <gui/Surface.h> #include <ui/DisplayInfo.h> #include <utils/Looper.h> +#include <thread> +#include <atomic> + namespace android { namespace uirenderer { namespace test { @@ -39,15 +43,29 @@ public: TestContext(); ~TestContext(); + // Must be called before surface(); + void setRenderOffscreen(bool renderOffscreen) { + LOG_ALWAYS_FATAL_IF(mSurface.get(), + "Must be called before surface is created"); + mRenderOffscreen = renderOffscreen; + } + sp<Surface> surface(); void waitForVsync(); private: + void createSurface(); + void createWindowSurface(); + void createOffscreenSurface(); + sp<SurfaceComposerClient> mSurfaceComposerClient; sp<SurfaceControl> mSurfaceControl; + sp<BufferItemConsumer> mConsumer; DisplayEventReceiver mDisplayEventReceiver; sp<Looper> mLooper; + sp<Surface> mSurface; + bool mRenderOffscreen; }; } // namespace test diff --git a/libs/hwui/tests/common/TestListViewSceneBase.cpp b/libs/hwui/tests/common/TestListViewSceneBase.cpp new file mode 100644 index 000000000000..847a6ff1181d --- /dev/null +++ b/libs/hwui/tests/common/TestListViewSceneBase.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TestListViewSceneBase.h" + +#include "TestContext.h" +#include "TestUtils.h" + +#include <utils/Color.h> + +namespace android { +namespace uirenderer { +namespace test { + +void TestListViewSceneBase::createContent(int width, int height, TestCanvas& canvas) { + srand(0); + mItemHeight = dp(60); + mItemSpacing = dp(16); + mItemWidth = std::min((height - mItemSpacing * 2), (int)dp(300)); + mItemLeft = (width - mItemWidth) / 2; + int heightWithSpacing = mItemHeight + mItemSpacing; + for (int y = 0; y < height + (heightWithSpacing - 1); y += heightWithSpacing) { + int id = mListItems.size(); + auto setup = std::bind(&TestListViewSceneBase::createListItem, this, std::placeholders::_1, + std::placeholders::_2, id, mItemWidth, mItemHeight); + auto node = TestUtils::createNode(mItemLeft, y, mItemLeft + mItemWidth, + y + mItemHeight, setup); + mListItems.push_back(node); + } + mListView = TestUtils::createNode(0, 0, width, height, + [this](RenderProperties& props, TestCanvas& canvas) { + for (size_t ci = 0; ci < mListItems.size(); ci++) { + canvas.drawRenderNode(mListItems[ci].get()); + } + }); + + canvas.drawColor(Color::Grey_500, SkXfermode::kSrcOver_Mode); + canvas.drawRenderNode(mListView.get()); +} + +void TestListViewSceneBase::doFrame(int frameNr) { + int scrollPx = dp(frameNr) * 3; + int itemIndexOffset = scrollPx / (mItemSpacing + mItemHeight); + int pxOffset = -(scrollPx % (mItemSpacing + mItemHeight)); + + TestCanvas canvas( + mListView->stagingProperties().getWidth(), + mListView->stagingProperties().getHeight()); + for (size_t ci = 0; ci < mListItems.size(); ci++) { + // update item position + auto listItem = mListItems[(ci + itemIndexOffset) % mListItems.size()]; + int top = ((int)ci) * (mItemSpacing + mItemHeight) + pxOffset; + listItem->mutateStagingProperties().setLeftTopRightBottom( + mItemLeft, top, mItemLeft + mItemWidth, top + mItemHeight); + listItem->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + + // draw it to parent DisplayList + canvas.drawRenderNode(mListItems[ci].get()); + } + mListView->setStagingDisplayList(canvas.finishRecording(), nullptr); +} + +} // namespace test +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/tests/common/TestListViewSceneBase.h b/libs/hwui/tests/common/TestListViewSceneBase.h new file mode 100644 index 000000000000..8ffe9929bbd9 --- /dev/null +++ b/libs/hwui/tests/common/TestListViewSceneBase.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "TestScene.h" +#include <RenderNode.h> +#include <RenderProperties.h> + +namespace android { +namespace uirenderer { +namespace test { + +class TestListViewSceneBase : public TestScene { +public: + virtual void createListItem(RenderProperties& props, TestCanvas& canvas, int id, + int itemWidth, int itemHeight) = 0; +private: + int mItemHeight; + int mItemSpacing; + int mItemWidth; + int mItemLeft; + sp<RenderNode> mListView; + std::vector< sp<RenderNode> > mListItems; + + void createContent(int width, int height, TestCanvas& canvas) override; + void doFrame(int frameNr) override; +}; + +} // namespace test +} // namespace uirenderer +} // namespace android diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h index 706f2ff75222..4813ff0de174 100644 --- a/libs/hwui/tests/common/TestScene.h +++ b/libs/hwui/tests/common/TestScene.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef TESTS_TESTSCENE_H -#define TESTS_TESTSCENE_H + +#pragma once #include <string> #include <unordered_map> @@ -22,14 +22,9 @@ namespace android { namespace uirenderer { class RenderNode; - -#if HWUI_NEW_OPS class RecordingCanvas; + typedef RecordingCanvas TestCanvas; -#else -class DisplayListCanvas; -typedef DisplayListCanvas TestCanvas; -#endif namespace test { @@ -38,6 +33,7 @@ public: struct Options { int count = 0; int reportFrametimeWeight = 0; + bool renderOffscreen = false; }; template <class T> @@ -75,5 +71,3 @@ public: } // namespace test } // namespace uirenderer } // namespace android - -#endif /* TESTS_TESTSCENE_H */ diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index c762eed616e4..930067a9b2cc 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -20,6 +20,9 @@ #include "DeferredLayerUpdater.h" #include "LayerRenderer.h" +#include <renderthread/EglManager.h> +#include <utils/Unicode.h> + namespace android { namespace uirenderer { @@ -68,7 +71,10 @@ void TestUtils::layoutTextUnscaled(const SkPaint& paint, const char* text, SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry); SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I()); while (*text != '\0') { - SkUnichar unichar = SkUTF8_NextUnichar(&text); + size_t nextIndex = 0; + int32_t unichar = utf32_from_utf8_at(text, 4, 0, &nextIndex); + text += nextIndex; + glyph_t glyph = autoCache.getCache()->unicharToGlyph(unichar); autoCache.getCache()->unicharToGlyph(unichar); @@ -107,12 +113,18 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, void TestUtils::TestTask::run() { // RenderState only valid once RenderThread is running, so queried here - RenderState& renderState = renderthread::RenderThread::getInstance().renderState(); + renderthread::RenderThread& renderThread = renderthread::RenderThread::getInstance(); + bool hasEglContext = renderThread.eglManager().hasEglContext(); + RenderState& renderState = renderThread.renderState(); + if (!hasEglContext) { + renderState.onGLContextCreated(); + } - renderState.onGLContextCreated(); - rtCallback(renderthread::RenderThread::getInstance()); - renderState.flush(Caches::FlushMode::Full); - renderState.onGLContextDestroyed(); + rtCallback(renderThread); + if (!hasEglContext) { + renderState.flush(Caches::FlushMode::Full); + renderState.onGLContextDestroyed(); + } } std::unique_ptr<uint16_t[]> TestUtils::asciiToUtf16(const char* str) { diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index 4536bef6d391..9f7fee262acf 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef TEST_UTILS_H -#define TEST_UTILS_H + +#pragma once #include <DeviceInfo.h> #include <DisplayList.h> @@ -25,24 +25,15 @@ #include <renderthread/RenderThread.h> #include <Snapshot.h> -#if HWUI_NEW_OPS #include <RecordedOp.h> #include <RecordingCanvas.h> -#else -#include <DisplayListOp.h> -#include <DisplayListCanvas.h> -#endif #include <memory> namespace android { namespace uirenderer { -#if HWUI_NEW_OPS typedef RecordingCanvas TestCanvas; -#else -typedef DisplayListCanvas TestCanvas; -#endif #define EXPECT_MATRIX_APPROX_EQ(a, b) \ EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b)) @@ -251,5 +242,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* TEST_UTILS_H */ diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp index f184411b4139..a61f6d0f1e7c 100644 --- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp +++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp @@ -17,8 +17,8 @@ #include "TestSceneBase.h" #include "utils/Color.h" -#include <minikin/Layout.h> #include <hwui/Paint.h> +#include <minikin/Layout.h> #include <cstdio> @@ -56,7 +56,7 @@ public: for (int i = 0; i < 5; i++) { paint.setTextSize(10 + (frameNr % 20) + i * 20); canvas.drawText(text.get(), 0, textLength, textLength, - 0, 100 * (i + 2), kBidi_Force_LTR, paint, nullptr); + 0, 100 * (i + 2), minikin::kBidi_Force_LTR, paint, nullptr); } container->setStagingDisplayList(canvas.finishRecording(), nullptr); diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp new file mode 100644 index 000000000000..ba6074fa7840 --- /dev/null +++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TestSceneBase.h" +#include "tests/common/TestListViewSceneBase.h" + +#include <SkGradientShader.h> + +class ListOfFadedTextAnimation; + +static TestScene::Registrar _ListOfFadedTextAnimation(TestScene::Info{ + "fadingedges", + "A mock ListView of scrolling text with faded edge. Doesn't re-bind/re-record views" + "as they are recycled, so won't upload much content (either glyphs, or bitmaps).", + TestScene::simpleCreateScene<ListOfFadedTextAnimation> +}); + +class ListOfFadedTextAnimation : public TestListViewSceneBase { + void createListItem(RenderProperties& props, TestCanvas& canvas, int id, + int itemWidth, int itemHeight) override { + canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode); + int length = dp(100); + canvas.saveLayer(0, 0, length, itemHeight, nullptr, SaveFlags::HasAlphaLayer); + SkPaint textPaint; + textPaint.setTextSize(dp(20)); + textPaint.setAntiAlias(true); + TestUtils::drawUtf8ToCanvas(&canvas, "not that long long text", textPaint, dp(10), dp(30)); + + SkPoint pts[2]; + pts[0].set(0, 0); + pts[1].set(0, 1); + + SkColor colors[2] = {Color::Black, Color::Transparent}; + SkAutoTUnref<SkShader> s(SkGradientShader::CreateLinear(pts, colors, NULL, 2, + SkShader::kClamp_TileMode)); + + SkMatrix matrix; + matrix.setScale(1, length); + matrix.postRotate(-90); + SkPaint fadingPaint; + fadingPaint.setShader(s->newWithLocalMatrix(matrix))->unref(); + SkXfermode* mode = SkXfermode::Create(SkXfermode::kDstOut_Mode); + fadingPaint.setXfermode(mode); + canvas.drawRect(0, 0, length, itemHeight, fadingPaint); + canvas.restore(); + } +}; diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp index 8035dc45f23c..a614044b2468 100644 --- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp +++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp @@ -15,7 +15,7 @@ */ #include "TestSceneBase.h" -#include "utils/Color.h" +#include "tests/common/TestListViewSceneBase.h" #include <cstdio> @@ -28,58 +28,8 @@ static TestScene::Registrar _ListView(TestScene::Info{ TestScene::simpleCreateScene<ListViewAnimation> }); -class ListViewAnimation : public TestScene { -public: - int cardHeight; - int cardSpacing; - int cardWidth; - int cardLeft; - sp<RenderNode> listView; - std::vector< sp<RenderNode> > cards; - void createContent(int width, int height, TestCanvas& canvas) override { - srand(0); - cardHeight = dp(60); - cardSpacing = dp(16); - cardWidth = std::min((height - cardSpacing * 2), (int)dp(300)); - cardLeft = (width - cardWidth) / 2; - - for (int y = 0; y < height + (cardHeight + cardSpacing - 1); y += (cardHeight + cardSpacing)) { - cards.push_back(createCard(cards.size(), y)); - } - listView = TestUtils::createNode(0, 0, width, height, - [this](RenderProperties& props, TestCanvas& canvas) { - for (size_t ci = 0; ci < cards.size(); ci++) { - canvas.drawRenderNode(cards[ci].get()); - } - }); - - canvas.drawColor(Color::Grey_500, SkXfermode::kSrcOver_Mode); - canvas.drawRenderNode(listView.get()); - } - - void doFrame(int frameNr) override { - int scrollPx = dp(frameNr) * 3; - int cardIndexOffset = scrollPx / (cardSpacing + cardHeight); - int pxOffset = -(scrollPx % (cardSpacing + cardHeight)); - - TestCanvas canvas( - listView->stagingProperties().getWidth(), - listView->stagingProperties().getHeight()); - for (size_t ci = 0; ci < cards.size(); ci++) { - // update card position - auto card = cards[(ci + cardIndexOffset) % cards.size()]; - int top = ((int)ci) * (cardSpacing + cardHeight) + pxOffset; - card->mutateStagingProperties().setLeftTopRightBottom( - cardLeft, top, cardLeft + cardWidth, top + cardHeight); - card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); - - // draw it to parent DisplayList - canvas.drawRenderNode(cards[ci].get()); - } - listView->setStagingDisplayList(canvas.finishRecording(), nullptr); - } -private: - SkBitmap createRandomCharIcon() { +class ListViewAnimation : public TestListViewSceneBase { + SkBitmap createRandomCharIcon(int cardHeight) { int size = cardHeight - (dp(10) * 2); SkBitmap bitmap = TestUtils::createSkBitmap(size, size); SkCanvas canvas(bitmap); @@ -97,7 +47,10 @@ private: paint.setTextAlign(SkPaint::kCenter_Align); paint.setTextSize(size / 2); char charToShow = 'A' + (rand() % 26); - canvas.drawText(&charToShow, 1, size / 2, /*approximate centering*/ size * 0.7, paint); + const SkPoint pos[] = {{ + SkIntToScalar(size / 2), + /*approximate centering*/ SkFloatToScalar(size * 0.7f)}}; + canvas.drawPosText(&charToShow, 1, pos, paint); return bitmap; } @@ -117,34 +70,31 @@ private: return bitmap; } - sp<RenderNode> createCard(int cardId, int top) { - return TestUtils::createNode(cardLeft, top, cardLeft + cardWidth, top + cardHeight, - [this, cardId](RenderProperties& props, TestCanvas& canvas) { - static SkBitmap filledBox = createBoxBitmap(true); - static SkBitmap strokedBox = createBoxBitmap(false); - - // TODO: switch to using round rect clipping, once merging correctly handles that - SkPaint roundRectPaint; - roundRectPaint.setAntiAlias(true); - roundRectPaint.setColor(Color::White); - canvas.drawRoundRect(0, 0, cardWidth, cardHeight, dp(6), dp(6), roundRectPaint); - - SkPaint textPaint; - textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500); - textPaint.setTextSize(dp(20)); - textPaint.setAntiAlias(true); - char buf[256]; - snprintf(buf, sizeof(buf), "This card is #%d", cardId); - TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, cardHeight, dp(25)); - textPaint.setTextSize(dp(15)); - TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint, - cardHeight, dp(45)); - - canvas.drawBitmap(createRandomCharIcon(), dp(10), dp(10), nullptr); - - const SkBitmap& boxBitmap = rand() % 2 ? filledBox : strokedBox; - canvas.drawBitmap(boxBitmap, cardWidth - dp(10) - boxBitmap.width(), dp(10), nullptr); - }); + void createListItem(RenderProperties& props, TestCanvas& canvas, int cardId, + int itemWidth, int itemHeight) override { + static SkBitmap filledBox = createBoxBitmap(true); + static SkBitmap strokedBox = createBoxBitmap(false); + // TODO: switch to using round rect clipping, once merging correctly handles that + SkPaint roundRectPaint; + roundRectPaint.setAntiAlias(true); + roundRectPaint.setColor(Color::White); + canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint); + + SkPaint textPaint; + textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500); + textPaint.setTextSize(dp(20)); + textPaint.setAntiAlias(true); + char buf[256]; + snprintf(buf, sizeof(buf), "This card is #%d", cardId); + TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, itemHeight, dp(25)); + textPaint.setTextSize(dp(15)); + TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint, + itemHeight, dp(45)); + + canvas.drawBitmap(createRandomCharIcon(itemHeight), dp(10), dp(10), nullptr); + + const SkBitmap& boxBitmap = rand() % 2 ? filledBox : strokedBox; + canvas.drawBitmap(boxBitmap, itemWidth - dp(10) - boxBitmap.width(), dp(10), nullptr); } }; diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h index 935ddcf9212d..792312a6a7a4 100644 --- a/libs/hwui/tests/common/scenes/TestSceneBase.h +++ b/libs/hwui/tests/common/scenes/TestSceneBase.h @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef TESTS_SCENES_TESTSCENEBASE_H -#define TESTS_SCENES_TESTSCENEBASE_H -#include "DisplayListCanvas.h" +#pragma once + #include "RecordingCanvas.h" #include "RenderNode.h" #include "tests/common/TestContext.h" @@ -30,5 +29,3 @@ using namespace android; using namespace android::uirenderer; using namespace android::uirenderer::renderthread; using namespace android::uirenderer::test; - -#endif /* TESTS_SCENES_TESTSCENEBASE_H_ */ diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp index c5af06160b62..f03dcbf4c24c 100644 --- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp +++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp @@ -22,6 +22,7 @@ #include "renderthread/RenderProxy.h" #include "renderthread/RenderTask.h" +#include <benchmark/benchmark.h> #include <cutils/log.h> #include <gui/Surface.h> #include <ui/PixelFormat.h> @@ -41,7 +42,7 @@ public: template<class T> class ModifiedMovingAverage { public: - ModifiedMovingAverage(int weight) : mWeight(weight) {} + explicit ModifiedMovingAverage(int weight) : mWeight(weight) {} T add(T today) { if (!mHasValue) { @@ -62,13 +63,62 @@ private: T mAverage; }; -void run(const TestScene::Info& info, const TestScene::Options& opts) { +void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options& opts, + benchmark::BenchmarkReporter* reporter, RenderProxy* proxy, + double durationInS) { + using namespace benchmark; + + struct ReportInfo { + int percentile; + const char* suffix; + }; + + static std::array<ReportInfo, 4> REPORTS = { + ReportInfo { 50, "_50th" }, + ReportInfo { 90, "_90th" }, + ReportInfo { 95, "_95th" }, + ReportInfo { 99, "_99th" }, + }; + + // Although a vector is used, it must stay with only a single element + // otherwise the BenchmarkReporter will automatically compute + // mean and stddev which doesn't make sense for our usage + std::vector<BenchmarkReporter::Run> reports; + BenchmarkReporter::Run report; + report.benchmark_name = info.name; + report.iterations = static_cast<int64_t>(opts.count); + report.real_accumulated_time = durationInS; + report.cpu_accumulated_time = durationInS; + report.items_per_second = opts.count / durationInS; + reports.push_back(report); + reporter->ReportRuns(reports); + + // Pretend the percentiles are single-iteration runs of the test + // If rendering offscreen skip this as it's fps that's more interesting + // in that test case than percentiles. + if (!opts.renderOffscreen) { + for (auto& ri : REPORTS) { + reports[0].benchmark_name = info.name; + reports[0].benchmark_name += ri.suffix; + durationInS = proxy->frameTimePercentile(ri.percentile) / 1000.0; + reports[0].real_accumulated_time = durationInS; + reports[0].cpu_accumulated_time = durationInS; + reports[0].iterations = 1; + reports[0].items_per_second = 0; + reporter->ReportRuns(reports); + } + } +} + +void run(const TestScene::Info& info, const TestScene::Options& opts, + benchmark::BenchmarkReporter* reporter) { // Switch to the real display gDisplay = getBuiltInDisplay(); std::unique_ptr<TestScene> scene(info.createScene(opts)); TestContext testContext; + testContext.setRenderOffscreen(opts.renderOffscreen); // create the native surface const int width = gDisplay.w; @@ -87,11 +137,16 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) { proxy->loadSystemProperties(); proxy->initialize(surface); float lightX = width / 2.0; - proxy->setup(width, height, dp(800.0f), 255 * 0.075, 255 * 0.15); + proxy->setup(dp(800.0f), 255 * 0.075, 255 * 0.15); proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)}); // Do a few cold runs then reset the stats so that the caches are all hot - for (int i = 0; i < 5; i++) { + int warmupFrameCount = 5; + if (opts.renderOffscreen) { + // Do a few more warmups to try and boost the clocks up + warmupFrameCount = 10; + } + for (int i = 0; i < warmupFrameCount; i++) { testContext.waitForVsync(); nsecs_t vsync = systemTime(CLOCK_MONOTONIC); UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync); @@ -103,6 +158,7 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) { ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight); + nsecs_t start = systemTime(CLOCK_MONOTONIC); for (int i = 0; i < opts.count; i++) { testContext.waitForVsync(); nsecs_t vsync = systemTime(CLOCK_MONOTONIC); @@ -121,6 +177,13 @@ void run(const TestScene::Info& info, const TestScene::Options& opts) { } } } + proxy->fence(); + nsecs_t end = systemTime(CLOCK_MONOTONIC); - proxy->dumpProfileInfo(STDOUT_FILENO, DumpFlags::JankStats); + if (reporter) { + outputBenchmarkReport(info, opts, reporter, proxy.get(), + (end - start) / (double) s2ns(1)); + } else { + proxy->dumpProfileInfo(STDOUT_FILENO, DumpFlags::JankStats); + } } diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index 02a39501e647..ffeef4599774 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -14,11 +14,14 @@ * limitations under the License. */ +#include "tests/common/LeakChecker.h" #include "tests/common/TestScene.h" #include "protos/hwui.pb.h" #include "Properties.h" +#include <benchmark/benchmark.h> +#include <../src/sysinfo.h> #include <getopt.h> #include <stdio.h> #include <string> @@ -39,8 +42,10 @@ using namespace android::uirenderer::test; static int gRepeatCount = 1; static std::vector<TestScene::Info> gRunTests; static TestScene::Options gOpts; +std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter; -void run(const TestScene::Info& info, const TestScene::Options& opts); +void run(const TestScene::Info& info, const TestScene::Options& opts, + benchmark::BenchmarkReporter* reporter); static void printHelp() { printf(R"( @@ -121,6 +126,20 @@ static void moveToCpuSet(const char* cpusetName) { close(fd); } +static bool setBenchmarkFormat(const char* format) { + if (!strcmp(format, "tabular")) { + gBenchmarkReporter.reset(new benchmark::ConsoleReporter()); + } else if (!strcmp(format, "json")) { + gBenchmarkReporter.reset(new benchmark::JSONReporter()); + } else if (!strcmp(format, "csv")) { + gBenchmarkReporter.reset(new benchmark::CSVReporter()); + } else { + fprintf(stderr, "Unknown format '%s'", format); + return false; + } + return true; +} + // For options that only exist in long-form. Anything in the // 0-255 range is reserved for short options (which just use their ASCII value) namespace LongOpts { @@ -130,6 +149,8 @@ enum { WaitForGpu, ReportFrametime, CpuSet, + BenchmarkFormat, + Offscreen, }; } @@ -141,6 +162,8 @@ static const struct option LONG_OPTIONS[] = { { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu }, { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime }, { "cpuset", required_argument, nullptr, LongOpts::CpuSet }, + { "benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat }, + { "offscreen", no_argument, nullptr, LongOpts::Offscreen }, { 0, 0, 0, 0 } }; @@ -214,6 +237,20 @@ void parseOptions(int argc, char* argv[]) { moveToCpuSet(optarg); break; + case LongOpts::BenchmarkFormat: + if (!optarg) { + error = true; + break; + } + if (!setBenchmarkFormat(optarg)) { + error = true; + } + break; + + case LongOpts::Offscreen: + gOpts.renderOffscreen = true; + break; + case 'h': printHelp(); exit(EXIT_SUCCESS); @@ -237,12 +274,18 @@ void parseOptions(int argc, char* argv[]) { if (optind < argc) { do { const char* test = argv[optind++]; - auto pos = TestScene::testMap().find(test); - if (pos == TestScene::testMap().end()) { - fprintf(stderr, "Unknown test '%s'\n", test); - exit(EXIT_FAILURE); + if (!strcmp(test, "all")) { + for (auto& iter : TestScene::testMap()) { + gRunTests.push_back(iter.second); + } } else { - gRunTests.push_back(pos->second); + auto pos = TestScene::testMap().find(test); + if (pos == TestScene::testMap().end()) { + fprintf(stderr, "Unknown test '%s'\n", test); + exit(EXIT_FAILURE); + } else { + gRunTests.push_back(pos->second); + } } } while (optind < argc); } else { @@ -255,12 +298,36 @@ int main(int argc, char* argv[]) { gOpts.count = 150; parseOptions(argc, argv); + if (!gBenchmarkReporter && gOpts.renderOffscreen) { + gBenchmarkReporter.reset(new benchmark::ConsoleReporter()); + } + + if (gBenchmarkReporter) { + size_t name_field_width = 10; + for (auto&& test : gRunTests) { + name_field_width = std::max<size_t>(name_field_width, test.name.size()); + } + // _50th, _90th, etc... + name_field_width += 5; + + benchmark::BenchmarkReporter::Context context; + context.num_cpus = benchmark::NumCPUs(); + context.mhz_per_cpu = benchmark::CyclesPerSecond() / 1000000.0f; + context.cpu_scaling_enabled = benchmark::CpuScalingEnabled(); + context.name_field_width = name_field_width; + gBenchmarkReporter->ReportContext(context); + } for (int i = 0; i < gRepeatCount; i++) { for (auto&& test : gRunTests) { - run(test, gOpts); + run(test, gOpts, gBenchmarkReporter.get()); } } - printf("Success!\n"); + + if (gBenchmarkReporter) { + gBenchmarkReporter->Finalize(); + } + + LeakChecker::checkForLeaks(); return 0; } diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp index 06b68d1dea8f..ed3b84753eeb 100644 --- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp @@ -17,21 +17,13 @@ #include <benchmark/benchmark.h> #include "DisplayList.h" -#if HWUI_NEW_OPS #include "RecordingCanvas.h" -#else -#include "DisplayListCanvas.h" -#endif #include "tests/common/TestUtils.h" using namespace android; using namespace android::uirenderer; -#if HWUI_NEW_OPS typedef RecordingCanvas TestCanvas; -#else -typedef DisplayListCanvas TestCanvas; -#endif void BM_DisplayList_alloc(benchmark::State& benchState) { while (benchState.KeepRunning()) { @@ -169,3 +161,37 @@ void BM_CanvasState_translate(benchmark::State& benchState) { } } BENCHMARK(BM_CanvasState_translate); + +void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) { + sp<RenderNode> child = TestUtils::createNode(50, 50, 100, 100, + [](auto& props, auto& canvas) { + canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); + }); + + TestCanvas canvas(100, 100); + delete canvas.finishRecording(); + + while (benchState.KeepRunning()) { + canvas.resetRecording(200, 200); + canvas.setHighContrastText(false); + canvas.translate(0, 0); // mScrollX, mScrollY + + // Clip to padding + // Can expect ~25% of views to have clip to padding with a non-null padding + int clipRestoreCount = canvas.save(SaveFlags::MatrixClip); + canvas.clipRect(1, 1, 199, 199, SkRegion::kIntersect_Op); + + canvas.insertReorderBarrier(true); + + // Draw child loop + for (int i = 0; i < benchState.range_x(); i++) { + canvas.drawRenderNode(child.get()); + } + + canvas.insertReorderBarrier(false); + canvas.restoreToCount(clipRestoreCount); + + delete canvas.finishRecording(); + } +} +BENCHMARK(BM_DisplayListCanvas_basicViewGroupDraw)->Arg(1)->Arg(5)->Arg(10); diff --git a/libs/hwui/tests/microbench/TaskManagerBench.cpp b/libs/hwui/tests/microbench/TaskManagerBench.cpp index c6b9f3bca55f..cf47f273c144 100644 --- a/libs/hwui/tests/microbench/TaskManagerBench.cpp +++ b/libs/hwui/tests/microbench/TaskManagerBench.cpp @@ -29,7 +29,7 @@ class TrivialTask : public Task<char> {}; class TrivialProcessor : public TaskProcessor<char> { public: - TrivialProcessor(TaskManager* manager) + explicit TrivialProcessor(TaskManager* manager) : TaskProcessor(manager) {} virtual ~TrivialProcessor() {} virtual void onProcess(const sp<Task<char> >& task) override { diff --git a/libs/hwui/tests/microbench/how_to_run.txt b/libs/hwui/tests/microbench/how_to_run.txt index e6f80b278276..915fe5d959f9 100755 --- a/libs/hwui/tests/microbench/how_to_run.txt +++ b/libs/hwui/tests/microbench/how_to_run.txt @@ -1,4 +1,3 @@ mmm -j8 frameworks/base/libs/hwui && -adb push $ANDROID_PRODUCT_OUT/data/local/tmp/hwuimicro \ - /data/local/tmp/hwuimicro && - adb shell /data/local/tmp/hwuimicro +adb push $OUT/data/benchmarktest/hwuimicro/hwuimicro /data/benchmarktest/hwuimicro/hwuimicro && +adb shell /data/benchmarktest/hwuimicro/hwuimicro diff --git a/libs/hwui/tests/microbench/main.cpp b/libs/hwui/tests/microbench/main.cpp index a0157bc4f9ef..9771c85382b4 100644 --- a/libs/hwui/tests/microbench/main.cpp +++ b/libs/hwui/tests/microbench/main.cpp @@ -14,6 +14,19 @@ * limitations under the License. */ +#include "debug/GlesDriver.h" +#include "debug/NullGlesDriver.h" + #include <benchmark/benchmark.h> -BENCHMARK_MAIN(); +#include <memory> + +using namespace android; +using namespace android::uirenderer; + +int main(int argc, char** argv) { + debug::GlesDriver::replace(std::make_unique<debug::NullGlesDriver>()); + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + return 0; +} diff --git a/libs/hwui/tests/scripts/prep_buller.sh b/libs/hwui/tests/scripts/prep_buller.sh new file mode 100755 index 000000000000..b2f68bd44e7d --- /dev/null +++ b/libs/hwui/tests/scripts/prep_buller.sh @@ -0,0 +1,49 @@ +#buller is bullhead & angler (☞゚ヮ゚)☞ + +nr=$(adb shell cat /proc/cpuinfo | grep processor | wc -l) +cpubase=/sys/devices/system/cpu +gov=cpufreq/scaling_governor + +adb root +adb wait-for-device +adb shell stop thermal-engine +adb shell stop perfd + +# LITTLE cores +# 384000 460800 600000 672000 787200 864000 960000 1248000 1440000 +# BIG cores +# 384000 480000 633600 768000 864000 960000 1248000 1344000 1440000 +# 1536000 1632000 1689600 1824000 + +cpu=0 +S=960000 +while [ $((cpu < 4)) -eq 1 ]; do + echo "Setting cpu $cpu to $S hz" + adb shell "echo 1 > $cpubase/cpu${cpu}/online" + adb shell "echo userspace > $cpubase/cpu${cpu}/$gov" + adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_max_freq" + adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_min_freq" + adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_setspeed" + cpu=$(($cpu + 1)) +done + +while [ $((cpu < $nr)) -eq 1 ]; do + echo "disable cpu $cpu" + adb shell "echo 0 > $cpubase/cpu${cpu}/online" + cpu=$(($cpu + 1)) +done + +echo "setting GPU bus and idle timer" +adb shell "echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split" +adb shell "echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on" +adb shell "echo 10000 > /sys/class/kgsl/kgsl-3d0/idle_timer" + +#0 762 1144 1525 2288 3509 4173 5271 5928 7904 9887 11863 +adb shell "echo 11863 > /sys/class/devfreq/qcom,gpubw.70/min_freq" &> /dev/null +adb shell "echo 11863 > /sys/class/devfreq/qcom,gpubw.19/min_freq" &> /dev/null + +#600000000 510000000 450000000 390000000 305000000 180000000 +echo "performance mode, 305 MHz" +adb shell "echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor" +adb shell "echo 305000000 > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq" +adb shell "echo 305000000 > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq" diff --git a/libs/hwui/tests/scripts/prep_volantis.sh b/libs/hwui/tests/scripts/prep_volantis.sh index 0572ee55c9b9..6407844afa90 100755 --- a/libs/hwui/tests/scripts/prep_volantis.sh +++ b/libs/hwui/tests/scripts/prep_volantis.sh @@ -16,16 +16,8 @@ adb root adb wait-for-device -adb shell stop mpdecision adb shell stop perfd -adb shell stop -for pid in $( adb shell ps | awk '{ if ( $9 == "surfaceflinger" ) { print $2 } }' ); do - adb shell kill $pid -done -adb shell setprop debug.egl.traceGpuCompletion 1 -adb shell daemonize surfaceflinger -sleep 3 -adb shell setprop service.bootanim.exit 1 +adb shell stop thermal-engine # cpu possible frequencies # 204000 229500 255000 280500 306000 331500 357000 382500 408000 433500 459000 diff --git a/libs/hwui/tests/scripts/stopruntime.sh b/libs/hwui/tests/scripts/stopruntime.sh new file mode 100644 index 000000000000..bb8fcb6f3ee2 --- /dev/null +++ b/libs/hwui/tests/scripts/stopruntime.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +adb root +adb wait-for-device +adb shell stop + +for pid in $( adb shell ps | awk '{ if ( $9 == "surfaceflinger" ) { print $2 } }' ); do + adb shell kill $pid +done +adb shell setprop debug.egl.traceGpuCompletion 1 +adb shell daemonize surfaceflinger +sleep 3 +adb shell setprop service.bootanim.exit 1 diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp index af54e079daab..e5fc55611be3 100644 --- a/libs/hwui/tests/unit/FrameBuilderTests.cpp +++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp @@ -1953,7 +1953,7 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) { class PropertyTestRenderer : public TestRendererBase { public: - PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback) + explicit PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback) : mCallback(callback) {} void onRectOp(const RectOp& op, const BakedOpState& state) override { EXPECT_EQ(mIndex++, 0); @@ -2075,7 +2075,7 @@ void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData, std::function<void(RenderProperties&)> propSetupCallback) { class SaveLayerAlphaClipTestRenderer : public TestRendererBase { public: - SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData) + explicit SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData) : mOutData(outData) {} OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override { diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp index 95543d33b1ef..67e58e2aba0d 100644 --- a/libs/hwui/tests/unit/GlopBuilderTests.cpp +++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp @@ -85,9 +85,6 @@ static void expectTransformEq(Glop::Transform& expectedTransform, Glop::Transfor } static void expectGlopEq(Glop& expectedGlop, Glop& builtGlop) { -#if !HWUI_NEW_OPS - EXPECT_EQ(expectedGlop.bounds, builtGlop.bounds); -#endif expectBlendEq(expectedGlop.blend, builtGlop.blend); expectFillEq(expectedGlop.fill, builtGlop.fill); expectMeshEq(expectedGlop.mesh, builtGlop.mesh); @@ -138,9 +135,6 @@ RENDERTHREAD_TEST(GlopBuilder, rectSnapTest) { // unit quad also should be translate by additional (0.3, 0.3) to snap to exact pixels. goldenGlop->transform.modelView.loadTranslate(1.3, 1.3, 0); goldenGlop->transform.modelView.scale(99, 99, 1); -#if !HWUI_NEW_OPS - goldenGlop->bounds = android::uirenderer::Rect(1.70, 1.70, 100.70, 100.70); -#endif goldenGlop->transform.canvas = simpleTranslate; goldenGlop->fill.texture.filter = GL_NEAREST; expectGlopEq(*goldenGlop, glop); diff --git a/libs/hwui/tests/unit/MeshStateTests.cpp b/libs/hwui/tests/unit/MeshStateTests.cpp new file mode 100644 index 000000000000..0881fa246afd --- /dev/null +++ b/libs/hwui/tests/unit/MeshStateTests.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <debug/MockGlesDriver.h> +#include <debug/ScopedReplaceDriver.h> +#include <gtest/gtest.h> +#include <gmock/gmock.h> +#include <renderstate/MeshState.h> +#include <tests/common/TestUtils.h> + +using namespace android::uirenderer; +using namespace testing; + +RENDERTHREAD_TEST(MeshState, genOrUpdate) { + debug::ScopedReplaceDriver<debug::MockGlesDriver> driverRef; + auto& mockGlDriver = driverRef.get(); + EXPECT_CALL(mockGlDriver, glGenBuffers_(_, _)).WillOnce(SetArgPointee<1>(35)); + EXPECT_CALL(mockGlDriver, glBindBuffer_(_, 35)); + EXPECT_CALL(mockGlDriver, glBufferData_(_, _, _, _)); + + GLuint buffer = 0; + renderThread.renderState().meshState().genOrUpdateMeshBuffer(&buffer, 10, nullptr, GL_DYNAMIC_DRAW); +}
\ No newline at end of file diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp index 9cd504ec0af7..d75ceb200a88 100644 --- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp +++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp @@ -746,7 +746,7 @@ TEST(RecordingCanvas, drawText) { paint.setTextSize(20); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO"); - canvas.drawText(dst.get(), 0, 5, 5, 25, 25, kBidi_Force_LTR, paint, NULL); + canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::kBidi_Force_LTR, paint, NULL); }); int count = 0; @@ -770,7 +770,7 @@ TEST(RecordingCanvas, drawTextInHighContrast) { paint.setTextSize(20); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO"); - canvas.drawText(dst.get(), 0, 5, 5, 25, 25, kBidi_Force_LTR, paint, NULL); + canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::kBidi_Force_LTR, paint, NULL); }); int count = 0; diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp index cf76a8691dcd..132601efb543 100644 --- a/libs/hwui/tests/unit/RenderNodeTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeTests.cpp @@ -68,7 +68,7 @@ TEST(RenderNode, hasParents) { TEST(RenderNode, releasedCallback) { class DecRefOnReleased : public GlFunctorLifecycleListener { public: - DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {} + explicit DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {} void onGlFunctorReleased(Functor* functor) override { *mRefCnt -= 1; } @@ -105,8 +105,9 @@ TEST(RenderNode, releasedCallback) { RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) { ContextFactory contextFactory; - CanvasContext canvasContext(renderThread, false, nullptr, &contextFactory); - TreeInfo info(TreeInfo::MODE_RT_ONLY, canvasContext); + std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create( + renderThread, false, nullptr, &contextFactory)); + TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get()); DamageAccumulator damageAccumulator; info.damageAccumulator = &damageAccumulator; info.observer = nullptr; @@ -128,5 +129,5 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) { nullDLNode->prepareTree(info); } - canvasContext.destroy(nullptr); + canvasContext->destroy(nullptr); } diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp index 409a12d37693..d05bdbf1709e 100644 --- a/libs/hwui/tests/unit/main.cpp +++ b/libs/hwui/tests/unit/main.cpp @@ -15,19 +15,15 @@ */ #include "gtest/gtest.h" +#include "gmock/gmock.h" #include "Caches.h" +#include "debug/GlesDriver.h" +#include "debug/NullGlesDriver.h" #include "thread/TaskManager.h" -#include "tests/common/TestUtils.h" +#include "tests/common/LeakChecker.h" -#include <memunreachable/memunreachable.h> - -#include <cstdio> -#include <iostream> -#include <map> -#include <unordered_set> #include <signal.h> -#include <unistd.h> using namespace std; using namespace android; @@ -54,67 +50,6 @@ static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) { raise(sig); } -static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) { - // merge them all - UnreachableMemoryInfo merged; - unordered_set<uintptr_t> addrs; - merged.allocation_bytes = 0; - merged.leak_bytes = 0; - merged.num_allocations = 0; - merged.num_leaks = 0; - for (auto& info : infolist) { - // We'll be a little hazzy about these ones and just hope the biggest - // is the most accurate - merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes); - merged.num_allocations = max(merged.num_allocations, info.num_allocations); - for (auto& leak : info.leaks) { - if (addrs.find(leak.begin) == addrs.end()) { - merged.leaks.push_back(leak); - merged.num_leaks++; - merged.leak_bytes += leak.size; - addrs.insert(leak.begin); - } - } - } - - // Now log the result - if (merged.num_leaks) { - cout << endl << "Leaked memory!" << endl; - if (!merged.leaks[0].backtrace.num_frames) { - cout << "Re-run with 'setprop libc.debug.malloc.program hwui_unit_test'" - << endl << "and 'setprop libc.debug.malloc.options backtrace=8'" - << " to get backtraces" << endl; - } - cout << merged.ToString(false); - } -} - -static void checkForLeaks() { - // TODO: Until we can shutdown the RT thread we need to do this in - // two passes as GetUnreachableMemory has limited insight into - // thread-local caches so some leaks will not be properly tagged as leaks - nsecs_t before = systemTime(); - UnreachableMemoryInfo rtMemInfo; - TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) { - if (Caches::hasInstance()) { - Caches::getInstance().tasks.stop(); - } - // Check for leaks - if (!GetUnreachableMemory(rtMemInfo)) { - cerr << "Failed to get unreachable memory!" << endl; - return; - } - }); - UnreachableMemoryInfo uiMemInfo; - if (!GetUnreachableMemory(uiMemInfo)) { - cerr << "Failed to get unreachable memory!" << endl; - return; - } - logUnreachable({rtMemInfo, uiMemInfo}); - nsecs_t after = systemTime(); - cout << "Leak check took " << ns2ms(after - before) << "ms" << endl; -} - int main(int argc, char* argv[]) { // Register a crash handler struct sigaction sa; @@ -127,10 +62,15 @@ int main(int argc, char* argv[]) { gSigChain.insert(pair<int, struct sigaction>(sig, old_sa)); } + // Replace the default GLES driver + debug::GlesDriver::replace(std::make_unique<debug::NullGlesDriver>()); + // Run the tests testing::InitGoogleTest(&argc, argv); + testing::InitGoogleMock(&argc, argv); + int ret = RUN_ALL_TESTS(); - checkForLeaks(); + test::LeakChecker::checkForLeaks(); return ret; } diff --git a/libs/hwui/utils/NinePatchImpl.cpp b/libs/hwui/utils/NinePatchImpl.cpp index 985f3fb66814..2b59ca9266d1 100644 --- a/libs/hwui/utils/NinePatchImpl.cpp +++ b/libs/hwui/utils/NinePatchImpl.cpp @@ -111,15 +111,6 @@ void NinePatch::Draw(SkCanvas* canvas, const SkRect& bounds, const int32_t* xDivs = chunk.getXDivs(); const int32_t* yDivs = chunk.getYDivs(); - // if our SkCanvas were back by GL we should enable this and draw this as - // a mesh, which will be faster in most cases. - if ((false)) { - SkNinePatch::DrawMesh(canvas, bounds, bitmap, - xDivs, chunk.numXDivs, - yDivs, chunk.numYDivs, - paint); - return; - } if (kUseTrace) { gTrace = true; diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp index b3195c4bbbfb..b879f781bce1 100644 --- a/libs/hwui/utils/TestWindowContext.cpp +++ b/libs/hwui/utils/TestWindowContext.cpp @@ -16,7 +16,6 @@ #include "TestWindowContext.h" #include "AnimationContext.h" -#include "DisplayListCanvas.h" #include "IContextFactory.h" #include "RecordingCanvas.h" #include "RenderNode.h" @@ -28,6 +27,7 @@ #include "gui/Surface.h" #include "renderthread/RenderProxy.h" +#include <cutils/memory.h> namespace { @@ -57,7 +57,7 @@ class TestWindowContext::TestWindowData { public: - TestWindowData(SkISize size) : mSize(size) { + explicit TestWindowData(SkISize size) : mSize(size) { android::BufferQueue::createBufferQueue(&mProducer, &mConsumer); mCpuConsumer = new android::CpuConsumer(mConsumer, 1); mCpuConsumer->setName(android::String8("TestWindowContext")); @@ -86,14 +86,9 @@ public: mProxy->initialize(mAndroidSurface.get()); float lightX = mSize.width() / 2.0f; android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f }; - mProxy->setup(mSize.width(), mSize.height(), 800.0f, - 255 * 0.075f, 255 * 0.15f); + mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f); mProxy->setLightCenter(lightVector); -#if HWUI_NEW_OPS mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height())); -#else - mCanvas.reset(new android::uirenderer::DisplayListCanvas(mSize.width(), mSize.height())); -#endif } SkCanvas* prepareToDraw() { @@ -119,8 +114,8 @@ public: SkImageInfo::Make(mSize.width(), mSize.height(), kRGBA_8888_SkColorType, kPremul_SkAlphaType); bmp->allocPixels(destinationConfig); - sk_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED, - mSize.width() * mSize.height()); + android_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED, + mSize.width() * mSize.height() * 4); android::CpuConsumer::LockedBuffer nativeBuffer; android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer); @@ -171,11 +166,7 @@ private: std::unique_ptr<android::uirenderer::RenderNode> mRootNode; std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy; -#if HWUI_NEW_OPS std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas; -#else - std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas; -#endif android::sp<android::IGraphicBufferProducer> mProducer; android::sp<android::IGraphicBufferConsumer> mConsumer; android::sp<android::CpuConsumer> mCpuConsumer; diff --git a/libs/hwui/utils/VectorDrawableUtils.cpp b/libs/hwui/utils/VectorDrawableUtils.cpp index ca75c5945b7f..6f0c96db4b1e 100644 --- a/libs/hwui/utils/VectorDrawableUtils.cpp +++ b/libs/hwui/utils/VectorDrawableUtils.cpp @@ -198,12 +198,12 @@ static void drawArc(SkPath* p, /* Solve for intersecting unit circles */ double dsq = dx * dx + dy * dy; if (dsq == 0.0) { - ALOGW("Points are coincident"); + VECTOR_DRAWABLE_LOGD("Points are coincident"); return; /* Points are coincident */ } double disc = 1.0 / dsq - 1.0 / 4.0; if (disc < 0.0) { - ALOGW("Points are too far apart %f", dsq); + VECTOR_DRAWABLE_LOGD("Points are too far apart %f", dsq); float adjust = (float) (sqrt(dsq) / 1.99999); drawArc(p, x0, y0, x1, y1, a * adjust, b * adjust, theta, isMoreThanHalf, isPositiveArc); |