static void android_view_RenderNode_getTransformMatrix(JNIEnv* env, jobject clazz, jlong renderNodePtr, jlong outMatrixPtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr); renderNode->mutateStagingProperties().updateMatrix(); const SkMatrix* transformMatrix = renderNode->stagingProperties().getTransformMatrix(); if (transformMatrix) { *outMatrix = *transformMatrix; } else { outMatrix->setIdentity(); } }
virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override { if (CC_UNLIKELY(!mWeakRef || !info.updateWindowPositions)) return; Matrix4 transform; info.damageAccumulator->computeCurrentTransform(&transform); const RenderProperties& props = node.properties(); uirenderer::Rect bounds(props.getWidth(), props.getHeight()); transform.mapRect(bounds); bounds.left -= info.windowInsetLeft; bounds.right -= info.windowInsetLeft; bounds.top -= info.windowInsetTop; bounds.bottom -= info.windowInsetTop; if (CC_LIKELY(transform.isPureTranslate())) { // snap/round the computed bounds, so they match the rounding behavior // of the clear done in SurfaceView#draw(). bounds.snapToPixelBoundaries(); } else { // Conservatively round out so the punched hole (in the ZOrderOnTop = true case) // doesn't extend beyond the other window bounds.roundOut(); } incStrong(0); auto functor = std::bind( std::mem_fn(&SurfaceViewPositionUpdater::doUpdatePositionAsync), this, (jlong) info.canvasContext.getFrameNumber(), (jint) bounds.left, (jint) bounds.top, (jint) bounds.right, (jint) bounds.bottom); info.canvasContext.enqueueFrameWork(std::move(functor)); }
static void android_view_RenderNode_setDisplayList(JNIEnv* env, jobject clazz, jlong renderNodePtr, jlong displayListPtr) { class RemovedObserver : public TreeObserver { public: virtual void onMaybeRemovedFromTree(RenderNode* node) override { maybeRemovedNodes.insert(sp<RenderNode>(node)); } std::set< sp<RenderNode> > maybeRemovedNodes; }; RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); DisplayList* newData = reinterpret_cast<DisplayList*>(displayListPtr); RemovedObserver observer; renderNode->setStagingDisplayList(newData, &observer); for (auto& node : observer.maybeRemovedNodes) { if (node->hasParents()) continue; onRenderNodeRemoved(env, node.get()); } }
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 }
void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayList* subtree) { if (subtree) { TextureCache& cache = Caches::getInstance().textureCache; info.out.hasFunctors |= subtree->getFunctors().size(); for (auto&& bitmapResource : subtree->getBitmapResources()) { void* ownerToken = &info.canvasContext; info.prepareTextures = cache.prefetchAndMarkInUse(ownerToken, bitmapResource); } 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(); } } }
static jboolean android_view_RenderNode_hasIdentityMatrix(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->mutateStagingProperties().updateMatrix(); return !renderNode->stagingProperties().hasTransformMatrix(); }
static jboolean android_view_RenderNode_isPivotExplicitlySet(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); return renderNode->stagingProperties().isPivotExplicitlySet(); }
static jfloat android_view_RenderNode_getRotationY(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); return renderNode->stagingProperties().getRotationY(); }
static jboolean android_view_RenderNode_getClipToOutline(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); return renderNode->stagingProperties().getOutline().getShouldClip(); }
static void android_view_RenderNode_destroyRenderNode(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->decStrong(0); }
static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->animators().endAllStagingAnimators(); }
static void android_view_RenderNode_output(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->output(); }
static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject, jlong renderNodePtr, jobject surfaceview) { class SurfaceViewPositionUpdater : public RenderNode::PositionListener { public: SurfaceViewPositionUpdater(JNIEnv* env, jobject surfaceview) { env->GetJavaVM(&mVm); mWeakRef = env->NewWeakGlobalRef(surfaceview); } virtual ~SurfaceViewPositionUpdater() { jnienv()->DeleteWeakGlobalRef(mWeakRef); mWeakRef = nullptr; } virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override { if (CC_UNLIKELY(!mWeakRef || !info.updateWindowPositions)) return; Matrix4 transform; info.damageAccumulator->computeCurrentTransform(&transform); const RenderProperties& props = node.properties(); uirenderer::Rect bounds(props.getWidth(), props.getHeight()); transform.mapRect(bounds); bounds.left -= info.windowInsetLeft; bounds.right -= info.windowInsetLeft; bounds.top -= info.windowInsetTop; bounds.bottom -= info.windowInsetTop; if (CC_LIKELY(transform.isPureTranslate())) { // snap/round the computed bounds, so they match the rounding behavior // of the clear done in SurfaceView#draw(). bounds.snapToPixelBoundaries(); } else { // Conservatively round out so the punched hole (in the ZOrderOnTop = true case) // doesn't extend beyond the other window bounds.roundOut(); } incStrong(0); auto functor = std::bind( std::mem_fn(&SurfaceViewPositionUpdater::doUpdatePositionAsync), this, (jlong) info.canvasContext.getFrameNumber(), (jint) bounds.left, (jint) bounds.top, (jint) bounds.right, (jint) bounds.bottom); info.canvasContext.enqueueFrameWork(std::move(functor)); } virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override { if (CC_UNLIKELY(!mWeakRef || (info && !info->updateWindowPositions))) return; ATRACE_NAME("SurfaceView position lost"); JNIEnv* env = jnienv(); jobject localref = env->NewLocalRef(mWeakRef); if (CC_UNLIKELY(!localref)) { jnienv()->DeleteWeakGlobalRef(mWeakRef); mWeakRef = nullptr; return; } env->CallVoidMethod(localref, gSurfaceViewPositionLostMethod, info ? info->canvasContext.getFrameNumber() : 0); env->DeleteLocalRef(localref); } private: JNIEnv* jnienv() { JNIEnv* env; if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", mVm); } return env; } void doUpdatePositionAsync(jlong frameNumber, jint left, jint top, jint right, jint bottom) { ATRACE_NAME("Update SurfaceView position"); JNIEnv* env = jnienv(); jobject localref = env->NewLocalRef(mWeakRef); if (CC_UNLIKELY(!localref)) { env->DeleteWeakGlobalRef(mWeakRef); mWeakRef = nullptr; } else { env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod, frameNumber, left, top, right, bottom); env->DeleteLocalRef(localref); } // We need to release ourselves here decStrong(0); } JavaVM* mVm; jobject mWeakRef; }; RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->setPositionListener(new SurfaceViewPositionUpdater(env, surfaceview)); }
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); }
static jfloat android_view_RenderNode_getPivotY(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->mutateStagingProperties().updateMatrix(); return renderNode->stagingProperties().getPivotY(); }
static void android_view_RenderNode_addAnimator(JNIEnv* env, jobject clazz, jlong renderNodePtr, jlong animatorPtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr); renderNode->addAnimator(animator); }
int main() { createTestEnvironment(); // create the native surface const int width = gDisplay.w; const int height = gDisplay.h; sp<SurfaceControl> control = createWindow(width, height); sp<Surface> surface = control->getSurface(); RenderNode* rootNode = new RenderNode(); rootNode->incStrong(0); rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height); rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); rootNode->mutateStagingProperties().setClipToBounds(false); rootNode->setPropertyFieldsDirty(RenderNode::GENERIC); ContextFactory factory; RenderProxy* proxy = new RenderProxy(false, rootNode, &factory); proxy->loadSystemProperties(); proxy->initialize(surface); float lightX = width / 2.0; proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)}, dp(800.0f), 255 * 0.075, 255 * 0.15); android::uirenderer::Rect DUMMY; std::vector< sp<RenderNode> > cards; DisplayListRenderer* renderer = startRecording(rootNode); renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); renderer->insertReorderBarrier(true); for (int x = dp(16); x < (width - dp(116)); x += dp(116)) { for (int y = dp(16); y < (height - dp(116)); y += dp(116)) { sp<RenderNode> card = createCard(x, y, dp(100), dp(100)); renderer->drawRenderNode(card.get(), DUMMY, 0); cards.push_back(card); } } renderer->insertReorderBarrier(false); endRecording(renderer, rootNode); for (int i = 0; i < 150; i++) { ATRACE_NAME("UI-Draw Frame"); for (size_t ci = 0; ci < cards.size(); ci++) { cards[ci]->mutateStagingProperties().setTranslationX(i); cards[ci]->mutateStagingProperties().setTranslationY(i); cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); } nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC); proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density); usleep(12000); } sleep(5); delete proxy; rootNode->decStrong(0); printf("Success!\n"); return 0; }
static jint android_view_RenderNode_getDebugSize(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); return renderNode->getDebugSize(); }
static jboolean android_view_RenderNode_hasOverlappingRendering(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); return renderNode->stagingProperties().hasOverlappingRendering(); }
static void android_view_RenderNode_setDisplayListData(JNIEnv* env, jobject clazz, jlong renderNodePtr, jlong newDataPtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr); renderNode->setStagingDisplayList(newData); }
virtual void redraw( void ) { static bool first=true; static RenderNode rn; int i; double tbalance; GeoLoadManager::ResultT region; if (_internalRoot == NullFC) { initialize(); showAll(); } _cart->getSFMatrix()->setValue(_navigator.getMatrix()); updateHighlight(); _win->activate(); _win->frameInit(); if(first) { loadManager=new GeoLoadManager(useFaceDistribution); first=false; rn.determinePerformance(_win); } if(_win->getPort().size() < (serverCount+1)) { ViewportPtr vp,ovp=_win->getPort(0); addRefCP(ovp); addRefCP(ovp); TileCameraDecoratorPtr deco; for(int i=_win->getPort().size()-1;i<serverCount;i++) { cout << "Add new" << endl; loadManager->addRenderNode(rn,i); if(simulateRendering) { beginEditCP(_win); deco=TileCameraDecorator::create(); beginEditCP(deco); deco->setFullWidth ( _win->getWidth() ); deco->setFullHeight( _win->getHeight() ); deco->setDecoratee( ovp->getCamera() ); vp=Viewport::create(); beginEditCP(vp); vp->setRoot ( ovp->getRoot() ); /* SkyBackgroundPtr sky = SkyBackground::create(); beginEditCP(sky); sky->setSphereRes(16); sky->getMFSkyColor()->addValue(Color3f(0, 0, .2)); sky->getMFSkyAngle()->addValue(Pi / 2); sky->getMFSkyColor()->addValue(Color3f(.6, .6, 1)); sky->getMFGroundColor()->addValue(Color3f(0, .3, 1)); sky->getMFGroundAngle()->addValue(Pi / 2); sky->getMFGroundColor()->addValue(Color3f(1, .3, 0)); endEditCP(sky); vp->setBackground( sky ); */ vp->setBackground( ovp->getBackground() ); vp->getMFForegrounds()->setValues( ovp->getForegrounds() ); vp->setCamera(deco); _win->addPort(vp); endEditCP(_win); endEditCP(vp); endEditCP(deco); } } } tbalance = -getSystemTime(); loadManager->update(_win->getPort()[0]->getRoot()); loadManager->balance(_win->getPort()[0],false,region); tbalance += getSystemTime(); if(simulateRendering) { ViewportPtr vp; TileCameraDecoratorPtr deco; for(i=0;i<region.size();i+=4) { #if 1 cout << "Region: " << i << " "; cout << region[i+0] << " "; cout << region[i+1] << " "; cout << region[i+2] << " "; cout << region[i+3] << endl; if(region[i+0] >= region[i+2]) { cout << "!!!" << endl; region[i+2]++; } if(region[i+1] >= region[i+3]) { cout << "!!!" << endl; region[i+3]++; } #endif vp=_win->getPort()[i/4+1]; deco=TileCameraDecoratorPtr::dcast(vp->getCamera()); beginEditCP(deco); beginEditCP(vp); vp->setSize(region[i+0], region[i+1], region[i+2], region[i+3]); deco->setSize(region[i+0]/(float)_win->getWidth(), region[i+1]/(float)_win->getHeight(), region[i+2]/(float)_win->getWidth(), region[i+3]/(float)_win->getHeight()); endEditCP(deco); endEditCP(vp); } } Time t,tmin,tmax; for(i=0;i<_win->getPort().size();++i) { t=-getSystemTime(); _action->setWindow( _win.getCPtr() ); _win->getPort(i)->render( _action ); glFlush(); t+=getSystemTime(); if(i==0) continue; if(i==1) { tmin=tmax=t; } else { if(t<tmin) tmin=t; if(t>tmax) tmax=t; } } if(!cache) printf("speed %5d %10.6f %10.6f %10.6f\n",_win->getPort().size()-1, tmin, tmax, tbalance); glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_SCISSOR_TEST); glViewport(0,0, _win->getWidth(), _win->getHeight()); if(viewVolume) loadManager->drawVolumes(_win); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0,_win->getWidth(), 0,_win->getHeight()); glDisable(GL_DEPTH_TEST); glEnable(GL_COLOR_MATERIAL); for(i=0;i<region.size();i+=4) { #if 0 cout << "Region: "; cout << region[i+0] << " "; cout << region[i+1] << " "; cout << region[i+2] << " "; cout << region[i+3] << endl; #endif glBegin(GL_LINE_LOOP); glColor3f(1, 1, 0); glVertex3f(region[i+0],region[i+1],0); glVertex3f(region[i+2],region[i+1],0); glVertex3f(region[i+2],region[i+3],0); glVertex3f(region[i+0],region[i+3],0); glEnd(); } glDisable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); if(doSave) { Int32 w,h; w=_win->getPort(0)->getPixelWidth(); h=_win->getPort(0)->getPixelHeight(); Image image(Image::OSG_RGB_PF, w,h,1, 1,1,0.0, NULL,true); ImageFileType *imgTransType=ImageFileHandler::the().getFileType("JPEG"); char filename[256]; if(imgTransType==NULL) { cerr << "Unknown image trans type" << endl; return; } sprintf(filename,"%s_%d.jpg",dumpImage,dumpImageNr++); // read buffer data into image glPixelStorei(GL_PACK_ALIGNMENT,1); glReadPixels(0,0,w,h, GL_RGB,GL_UNSIGNED_BYTE, image.getData()); imgTransType->write(image,filename); } _win->swap(); _win->frameExit(); }