Openglrenderer: Bitmap Too Large to Be Uploaded Into a Texture (5312x2988

UI Rendering is the act of generating a frame from your app and displaying information technology on the screen. To ensure that a user'due south interaction with your app is smooth, your app should render frames in nether 16ms to achieve threescore frames per second (why 60fps?). If your app suffers from slow UI rendering, and so the organisation is forced to skip frames and the user will perceive stuttering in your app. We call this jank.

To help you amend app quality, Android automatically monitors your app for jank and displays the data in the Android vitals dashboard. For information on how the information is collected, run into Play Panel docs.

If your app is experiencing jank, this page provides guidance on diagnosing and fixing the problem.

Identifying jank

Pinpointing the code in your app that is causing jank can be difficult. This department describes 3 methods for identifying jank:

  • Visual inspection
  • Systrace
  • Custom operation monitoring

Visual inspection lets y'all quickly run through all the use-cases in your app in a few minutes, simply information technology doesn't provide as much particular equally Systrace. Systrace provides more than details, but if you ran Systrace for all the apply-cases in your app, you'd be flooded with so much data that it'd be hard to clarify. Both visual inspection and systrace observe jank on your local device. If your jank cannot exist reproduced on local devices, y'all can build custom operation monitoring to measure specific parts of your app on devices running in the field.

With visual inspection

Visual inspection helps y'all identify the employ-cases that are producing jank. To perform a visual inspection, open your app and manually go through the different parts of your app and look out for UI that is janky. Here are some tips when performing visual inspections:

  • Run a release (or at least non-debuggable) version of your app. The ART runtime disables several of import optimizations in order to back up debugging features, so brand sure y'all're looking at something similar to what a user volition come across.
  • Enable Contour GPU Rendering. Contour GPU Rendering displays bars on the screen that requite you a quick visual representation of how much time it takes to render the frames of a UI window relative to the xvi-ms-per-frame benchmark. Each bar has colored components that map to a phase in the rendering pipeline, and so yous tin see which portion is taking the longest. For instance, if the frame spends a lot of time handling input, you should look at your app code that handles user input.
  • There are sure components, such as RecyclerView, that are a mutual source of jank. If your app uses those components, information technology'southward a good idea to run through those parts of the app.
  • Sometimes, jank can be reproduced just when the app is launched from a cold starting time.
  • Attempt running your app on a slower device to exacerbate the problem.

In one case yous've constitute employ-cases that produce jank, you might accept a good idea of what is causing the jank in your app. Only if y'all need more information, you can use Systrace to drill downwards further.

With Systrace

Although Systrace is a tool that shows what the entire device is doing, it can exist useful for identifying jank in your app. Systrace has minimal system overhead, so you lot will experience realistic jankiness during instrumentation.

Tape a trace with Systrace while performing the janky use-case on your device. Run into the Systrace Walkthrough for instructions on how to use Systrace. The systrace is broken upward by processes and threads. Wait for your app's process in Systrace, which should wait similar figure one.

Figure 1: systrace

The systrace in figure 1 contains the following data for identifying jank:

  1. Systrace shows when each frame is drawn and color codes each frame to highlight tiresome render times. This helps yous observe individual janky frames more accurately than visual inspection. For more information, see Inspect UI frames and alerts.
  2. Systrace detects issues in your app and displays alerts both in individual frames and the alerts panel. Post-obit directions in the alert is your best option.
  3. Parts of the Android framework and libraries, such as RecyclerView, incorporate trace markers. And so, the systrace timeline shows when those methods are executed on the UI thread and how long they take to execute.

After looking at the systrace output, in that location might be methods in your app that you suspect are causing jank. For an example, if the timeline shows that a slow frame is caused by RecyclerView taking a long time, you tin add together Trace markers to the relevant code and re-run systrace for more information. In the new systrace, the timeline will show when your app'due south methods are called and how long they took to execute.

If systrace doesn't show you details about why UI thread work is taking for a long time, so you'll need to apply Android CPU Profiler to record either a sampled or instrumented method trace. Generally, method traces are non proficient for identifying jank because they produce faux-positive janks due to heavy overhead and they can't see when threads are running vs blocked. Just, method traces can help you lot identify the methods in your app are taking the nearly time. After identifying those methods, add Trace markers and re-run systrace to encounter whether those methods are causing jank.

For more information, see Understanding Systrace.

With custom operation monitoring

If yous tin can't reproduce jank on a local device, you can build custom performance monitoring into your app to help identify the source of jank on devices in the field.

To do this, collect frame render times from specific parts of your app with FrameMetricsAggregator and record and analyze the data using Firebase Performance Monitoring.

To acquire more, see Use Firebase Operation Monitoring with Android Vitals.

Fixing jank

To fix jank, inspect which frames aren't completing in sixteen.7ms, and look for what is going wrong. Is Record View#describe taking abnormally long in some frames, or perchance Layout? Meet the Common sources of jank below for these problems, and others.

To avoid jank, long running tasks should be run asynchronously outside of the UI thread. E'er be aware of what thread your code is running on and use circumspection when posting non-footling tasks to the primary thread.

If yous have a complex and important chief UI for your app (maybe the fundamental scrolling listing), consider writing instrumentation tests that tin automatically detect slow render times and run the tests oftentimes to forestall regressions. For more information, run into the Automated Performance Testing Codelab.

Common sources of jank

The post-obit sections explain common sources of jank in apps and best practices for addressing them.

Scrollable lists

ListView and especially RecyclerView are commonly used for circuitous scrolling lists that are most susceptible to jank. They both comprise Systrace markers, so y'all can use Systrace to figure out whether they are contributing to jank in your app. Be sure to pass the command line argument -a <your-package-name> to get trace sections in RecyclerView (as well as any trace markers you added) to show upward. If available, follow the guidance of the alerts generated in the systrace output. Inside Systrace, you can click on RecyclerView-traced sections to encounter an caption of the piece of work RecyclerView is doing.

RecyclerView: notifyDataSetChanged

If you see every particular in your RecyclerView being rebound (and thus re-laid out and re-drawn) in one frame, make sure that you're not calling notifyDataSetChanged(), setAdapter(Adapter), or swapAdapter(Adapter, boolean) for small updates. Those methods signal that the entire listing content has inverse, and will show up in Systrace as RV FullInvalidate. Instead, use SortedList or DiffUtil to generate minimal updates when content changes or is added.

For example, consider an app that receives a new version of a list of news content from the server. When you post that info to the Adapter, it'southward possible to telephone call notifyDataSetChanged() every bit shown below:

Kotlin

fun onNewDataArrived(news: List<News>) {     myAdapter.news = news     myAdapter.notifyDataSetChanged() }            

Java

void onNewDataArrived(Listing<News> news) {     myAdapter.setNews(news);     myAdapter.notifyDataSetChanged(); }            

Only this comes with a big downside – if it's a fiddling change (mayhap a unmarried detail added to the top), the RecyclerView isn't enlightened – it is told to drop all its buried item state, and thus needs to rebind everything.

It'south much preferable to use DiffUtil, which volition calculate and acceleration minimal updates for yous.

Kotlin

fun onNewDataArrived(news: List<News>) {     val oldNews = myAdapter.items     val consequence = DiffUtil.calculateDiff(MyCallback(oldNews, news))     myAdapter.news = news     result.dispatchUpdatesTo(myAdapter) }            

Java

void onNewDataArrived(List<News> news) {     List<News> oldNews = myAdapter.getItems();     DiffResult result = DiffUtil.calculateDiff(new MyCallback(oldNews, news));     myAdapter.setNews(news);     result.dispatchUpdatesTo(myAdapter); }            

Just define your MyCallback as a DiffUtil.Callback implementation to inform DiffUtil how to inspect your lists.

RecyclerView: Nested RecyclerViews

Information technology's mutual to nest RecyclerViews, particularly with a vertical list of horizontally scrolling lists (like grids of apps on Play Store chief folio). This can piece of work great, just information technology's also a lot of views moving around. If you see a lot of inner items inflating when y'all get-go scroll down the page, you may desire to check that y'all're sharing RecyclerView.RecycledViewPoolsouthward betwixt inner (horizontal) RecyclerViews. By default, each RecyclerView will accept its own puddle of items. In the case with a dozen itemViews on screen at once though, it's problematic when itemViews tin can't be shared by the different horizontal lists, if all the rows are showing similar types of views.

Kotlin

class OuterAdapter : RecyclerView.Adapter<OuterAdapter.ViewHolder>() {      ...      override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {         // inflate inner item, find innerRecyclerView by ID…         val innerLLM = LinearLayoutManager(parent.context, LinearLayoutManager.HORIZONTAL, false)         innerRv.utilise {             layoutManager = innerLLM              recycledViewPool = sharedPool              }         return OuterAdapter.ViewHolder(innerRv)     }     ...            

Coffee

class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.ViewHolder> {     RecyclerView.RecycledViewPool sharedPool = new RecyclerView.RecycledViewPool();      ...      @Override     public void onCreateViewHolder(ViewGroup parent, int viewType) {         // inflate inner item, detect innerRecyclerView by ID…         LinearLayoutManager innerLLM = new LinearLayoutManager(parent.getContext(),                 LinearLayoutManager.HORIZONTAL);         innerRv.setLayoutManager(innerLLM);              innerRv.setRecycledViewPool(sharedPool);              render new OuterAdapter.ViewHolder(innerRv);      }     ...            

If yous desire to optimize further, you can also call setInitialPrefetchItemCount(int) on the inner RecyclerView's LinearLayoutManager. If for example you lot'll ever take iii.v items visible in a row, call innerLLM.setInitialItemPrefetchCount(4);. This will indicate to RecyclerView that when a horizontal row is about to come onscreen, it should effort to prefetch the items inside, if in that location's spare time on the UI thread.

RecyclerView: Too much inflation / Create taking too long

The prefetch feature in RecyclerView should help work around the toll of inflation in near cases by doing the work ahead of time, while the UI thread is idle. If y'all're seeing inflation during a frame (and not in a section labelled RV Prefetch), be sure you're testing on a recent device (Prefetch currently just supported on Android five.0 API Level 21 and higher) and using a recent version of the Back up Library.

If you frequently see inflation causing jank as new items come on screen, verify that you don't have more view types than yous need. The fewer the view types in a RecyclerView'due south content, the less inflation volition need to be done when new item types come on screen. If possible, merge view types where reasonable – if just an icon, colour, or piece of text changes between types, you can make that change at bind time, and avoid aggrandizement (reducing your app's memory footprint at the same time).

If your view types look good, look at reducing the cost of your inflation. Reducing unnecessary container and structural Views tin can help – consider building itemViews with ConstraintLayout, which can brand it easy to reduce structural Views. If you want to really optimize for performance, your items hierarchies are unproblematic, and you don't need circuitous theming and style features, consider calling the constructors yourself – note though, that it's often non worth the tradeoff of losing the simplicity and features of XML.

RecyclerView: Bind taking too long

Bind (that is, onBindViewHolder(VH, int)) should be very simple, and take much less than one millisecond for all simply the most complex items. Information technology merely should take POJO items from your adapter'southward internal item information, and phone call setters on views in the ViewHolder. If RV OnBindView is taking a long fourth dimension, verify that you're doing minimal piece of work in your bind code.

If you lot're using unproblematic POJO objects to hold data in your adapter, y'all can completely avert writing the binding lawmaking in onBindViewHolder past using the Data Binding library.

RecyclerView or ListView: layout / draw taking likewise long

For issues with depict and layout, encounter the sections on Layout and Rendering Performance.

ListView: Inflation

Information technology'southward easy to accidentally disable recycling in ListView if you aren't careful. If you see aggrandizement every fourth dimension an item comes on screen, bank check that your implementation of Adapter.getView() is using, re-bounden, and returning the convertView parameter. If your getView() implementation always inflates, your app won't get the benefits of recycling in ListView. The structure of your getView() should nearly ever be similar to the implementation below:

Kotlin

fun getView(position: Int, convertView: View?, parent: ViewGroup): View {     render (convertView ?: layoutInflater.inflate(R.layout.my_layout, parent, false)).apply {         // … demark content from position to convertView …     } }            

Java

View getView(int position, View convertView, ViewGroup parent) {      if (convertView == null) {         // but inflate if no convertView passed         convertView = layoutInflater.inflate(R.layout.my_layout, parent, simulated)     }     // … bind content from position to convertView …     render convertView; }            

Layout performance

If Systrace shows that the Layout segment of Choreographer#doFrame is doing likewise much work, or doing work too often, that means you're hitting layout functioning issues. The layout operation of your app depends on what portion of the View bureaucracy has changing layout parameters or inputs.

Layout operation: Price

If the segments are longer than a few milliseconds, it'south possible that you're hit worst-case nesting performance for RelativeLayouts, or weighted-LinearLayouts. Each of these layouts can trigger multiple measure/layout passes of its children, so nesting them can lead to O(n^2) behavior on the depth of nesting. Effort avoiding RelativeLayout or the weight feature of LinearLayout in all but the lowest leaf nodes of the hierarchy. At that place are a few means to practise this:

  • You can reorganize your structural views.
  • You can ascertain custom layout logic. See the optimize your layout guide for a specific example.
  • You can endeavour converting to ConstraintLayout, which provides similar features, without the performance drawbacks.

Layout performance: Frequency

Layout is expected to happen when new content comes on screen, for example when a new item scrolls into view in RecyclerView. If significant layout is happening on each frame, it's possible that you're animating layout, which is likely to crusade dropped frames. By and large, animations should be run on drawing backdrop of View (e.g. setTranslationX/Y/Z(), setRotation(), setAlpha(), etc…). These can all exist changed much more cheaply than layout properties (such as padding, or margins). Information technology'southward also much cheaper to change cartoon properties of a view, generally past calling a setter which triggers a invalidate(), followed past a draw(Canvas) in the side by side frame. This will re-record drawing operations for the view that is invalidated, and is besides generally much cheaper than layout.

Rendering performance

Android UI does work in two phases – Record View#draw, on the UI thread, and DrawFrame on the RenderThread. The first runs draw(Canvas) on every invalidated View, and may invoke calls into custom views or into your code. The second runs on the native RenderThread, but will operate based on work generated past the Record View#describe phase.

Rendering operation: UI Thread

If Record View#draw is taking a long fourth dimension, information technology's often the case that a bitmap is being painted on the UI thread. Painting to a bitmap uses CPU rendering, so you should generally avert this when possible. You can utilize method tracing with the Android CPU Profiler to see if this is the problem.

Painting to a bitmap is often washed when an app wants to decorate a bitmap earlier displaying it. Sometimes a ornamentation like adding rounded corners:

Kotlin

val pigment = Pigment().apply {     isAntiAlias = truthful } Canvas(roundedOutputBitmap).apply {     // draw a round rect to define shape:     drawRoundRect(             0f,             0f,             roundedOutputBitmap.width.toFloat(),             roundedOutputBitmap.height.toFloat(),             20f,             20f,             paint     )     paint.xfermode = PorterDuffXfermode(PorterDuff.Fashion.MULTIPLY)     // multiply content on summit, to make it rounded     drawBitmap(sourceBitmap, 0f, 0f, paint)     setBitmap(null)     // now roundedOutputBitmap has sourceBitmap inside, but as a circle }            

Java

Canvass bitmapCanvas = new Canvas(roundedOutputBitmap); Paint paint = new Paint(); paint.setAntiAlias(true); // depict a circular rect to define shape: bitmapCanvas.drawRoundRect(0, 0,         roundedOutputBitmap.getWidth(), roundedOutputBitmap.getHeight(), 20, 20, paint); pigment.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); // multiply content on top, to brand it rounded bitmapCanvas.drawBitmap(sourceBitmap, 0, 0, pigment); bitmapCanvas.setBitmap(zippo); // now roundedOutputBitmap has sourceBitmap inside, but equally a circumvolve            

If this is the sort of work you're doing on the UI thread, yous can instead do this on the decoding thread in the background. In some cases similar this one, you can even do the work at describe time, then if your Drawable or View code looks something similar this:

Kotlin

fun setBitmap(bitmap: Bitmap) {     mBitmap = bitmap     invalidate() }  override fun onDraw(sail: Canvas) {     canvas.drawBitmap(mBitmap, null, paint) }            

Coffee

void setBitmap(Bitmap bitmap) {     mBitmap = bitmap;     invalidate(); }  void onDraw(Canvas canvas) {     canvas.drawBitmap(mBitmap, nil, paint); }            

Y'all can replace it with this:

Kotlin

fun setBitmap(bitmap: Bitmap) {     shaderPaint.shader = BitmapShader(bitmap, Shader.TileMode.Clamp, Shader.TileMode.Clamp)     invalidate() }  override fun onDraw(canvas: Canvas) {     canvass.drawRoundRect(0f, 0f, width, height, 20f, 20f, shaderPaint) }            

Coffee

void setBitmap(Bitmap bitmap) {     shaderPaint.setShader(             new BitmapShader(bitmap, TileMode.Clamp, TileMode.Clamp));     invalidate(); }  void onDraw(Sail canvass) {     canvas.drawRoundRect(0, 0, width, height, 20, xx, shaderPaint); }            

Note that this can also often be washed for background protection (drawing a gradient on elevation of the Bitmap), and image filtering (with ColorMatrixColorFilter), two other common operations washed modifying bitmaps.

If y'all're drawing to a bitmap for another reason, perchance using information technology every bit a enshroud, effort and draw to the hardware accelerated Canvas passed to your View or Drawable directly, and if necessary, consider calling setLayerType() with LAYER_TYPE_HARDWARE to enshroud complex rendering output, and yet have advantage of GPU rendering.

Rendering functioning: RenderThread

Some canvas operations are inexpensive to record, but trigger expensive computation on the RenderThread. Systrace will generally call these out with alerts.

Canvas.saveLayer()

Avoid Sheet.saveLayer() – it can trigger expensive, uncached, off-screen rendering each frame. Though performance was improved in Android 6.0 (when optimizations were fabricated to avoid render target switching on the GPU), it's notwithstanding good to avoid this expensive API if possible, or at minimum, ensure y'all're passing the Sheet.CLIP_TO_LAYER_SAVE_FLAG (or calling a variant that doesn't take flags).

Animating big Paths

When Canvas.drawPath() is chosen on the hardware accelerated Canvas passed to Views, Android draws these paths first on CPU, and uploads them to the GPU. If you have large paths, avoid editing them from frame to frame, so they can be cached and drawn efficiently. drawPoints(), drawLines(), and drawRect/Circle/Oval/RoundRect() are more efficient – it's better to use them fifty-fifty if you end up using more draw calls.

Sheet.clipPath

clipPath(Path) triggers expensive clipping behavior, and should generally be avoided. When possible, opt for cartoon shapes, instead of clipping to non-rectangles. Information technology performs better and supports anti-aliasing. For example, the following clipPath call:

Kotlin

canvas.employ {     salve()     clipPath(circlePath)     drawBitmap(bitmap, 0f, 0f, pigment)     restore() }            

Coffee

canvass.save(); canvas.clipPath(circlePath); canvass.drawBitmap(bitmap, 0f, 0f, paint); canvass.restore();            

Can be instead expressed every bit:

Kotlin

pigment.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) // at draw fourth dimension: canvas.drawPath(circlePath, mPaint)            

Coffee

// 1 fourth dimension init: paint.setShader(new BitmapShader(bitmap, TileMode.Clench, TileMode.Clench)); // at draw time: canvass.drawPath(circlePath, mPaint);            

Bitmap uploads

Android displays bitmaps as OpenGL textures, and the first time a bitmap is displayed in a frame, it's uploaded to the GPU. You can come across this in Systrace as Upload width ten peak Texture. This can accept several milliseconds (see Figure 2), merely it's necessary to display the image with the GPU.

If these are taking a long time, first check the width and height numbers in the trace. Ensure that the bitmap existence displayed isn't significantly bigger than the area on screen it's showing in. If information technology is, that wastes upload time, and memory. More often than not Bitmap loading libraries provide easy means of requesting an appropriately sized Bitmap.

In Android seven.0, bitmap loading lawmaking (more often than not done by libraries) can call prepareToDraw() to trigger an upload early, before it'south needed. This way the upload happens early on, while the RenderThread is idle. This can be done later on decoding, or when binding a bitmap to a View, as long as you know the bitmap. Ideally, your bitmap loading library volition do this for you, but if yous're managing your own, or want to ensure you lot don't hit uploads on newer devices, yous can call prepareToDraw() in your ain code.

Figure two: An app spends more than 10ms in a frame uploading a ane.8 megapixel bitmap. Either reduce its size, or trigger information technology early on when decoded with prepareToDraw().

Thread scheduling delays

The thread scheduler is the role of the Android operating system in charge of deciding which threads in the organization should run, when, and for how long. Sometimes, jank occurs because your app'south UI Thread is blocked or non running. Systrace uses different colors (run across effigy 3) to point when a thread is Sleeping (gray), Runnable (bluish: it could run, but the scheduler hasn't picked it to run yet), Actively running (Green), or in Uninterruptible sleep (Ruby or Orange). This is extremely useful for debugging jank bug that are caused by thread scheduling delays.

Figure 3: highlights a catamenia when the UI Thread is sleeping.

Often long pauses in your app's execution are acquired by binder calls, the inter-process communication (IPC) mechanism on Android. On recent versions of Android, it's one of the most mutual reasons for the UI Thread to stop running. By and large, the fix is to avert calling functions that make binder calls; if it'due south unavoidable, you lot should enshroud the value, or movement work to groundwork threads. Equally codebases get larger, it'south easy to accidentally add a binder telephone call by invoking some low level method if you lot aren't conscientious – but it's only every bit easy to find and fix them with tracing.

If y'all have binder transactions, you can capture their telephone call stacks with the following adb commands:

          $ adb shell am trace-ipc start … utilize the app - scroll/animate ... $ adb beat out am trace-ipc stop --dump-file /data/local/tmp/ipc-trace.txt $ adb pull /data/local/tmp/ipc-trace.txt                  

Sometimes innocuous seeming calls similar getRefreshRate() can trigger folder transactions, and cause big problems when they're called frequently. Tracing periodically can help yous quickly find and fix these issues as they bear witness upwards.

Figure 4: shows the UI Thread sleeping due to folder transactions in a RV fling. Continue your bind logic unproblematic, and utilise trace-ipc to track down and remove binder calls.

If you aren't seeing folder activity, simply still aren't seeing your UI Thread run, be sure that you're not waiting on some lock or other operation from another thread. Typically, the UI thread shouldn't have to expect on results from other threads – other threads should post information to information technology.

Object allocation and garbage collection

Object allocation and garbage collection (GC) have get significantly less of an result since Fine art was introduced every bit the default runtime in Android 5.0, but it's still possible to counterbalance down your threads with this actress piece of work. It'south fine to allocate in response to a rare event that doesn't happen many times a second (similar a user clicking a button), only remember that each allocation comes with a cost. If it's in a tight loop that's called frequently, consider avoiding the allocation to lighten the load on the GC.

Systrace will show you if GC is running ofttimes, and the Android Memory Profiler can show you where allocations are coming from. If yous avert allocations when y'all can, especially in tight loops, you shouldn't accept a trouble.

Effigy v: shows a 94ms GC on the HeapTaskDaemon thread

On recent versions of Android, GC generally runs on a background thread named HeapTaskDaemon. Note that significant amounts of resource allotment can mean more CPU resource spent on GC equally shown in figure 5.

carollotagoink.blogspot.com

Source: https://developer.android.com/topic/performance/vitals/render

0 Response to "Openglrenderer: Bitmap Too Large to Be Uploaded Into a Texture (5312x2988"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel