Class DrawAtlas

java.lang.Object
icyllis.arc3d.granite.DrawAtlas
All Implemented Interfaces:
AutoCloseable

public class DrawAtlas extends Object implements AutoCloseable
This class manages one or more atlas textures on behalf of primitive draws in Device. The drawing processes that use the atlas add preceding UploadTasks when generating RenderPassTasks. The class provides facilities for using DrawTokens to detect data hazards. Plots that need uploads are tracked until it is impossible to add data without overwriting texels read by draws that have not yet been snapped to a RenderPassTask. At that point, the atlas will attempt to allocate a new atlas texture (or "page") of the same size, up to a maximum number of textures, and upload to that texture. If that's not possible, then the atlas will fail to add a subimage. This gives the Device the chance to end the current draw, snap a RenderpassTask, and begin a new one. Additional uploads will then succeed.

When the atlas has multiple pages, new uploads are prioritized to the lower index pages, i.e., it will try to upload to page 0 before page 1 or 2. To keep the atlas from continually using excess space, periodic garbage collection is needed to shift data from the higher index pages to the lower ones, and then eventually remove any pages that are no longer in use. "In use" is determined by using the AtlasToken system: After a DrawPass is snapped a subarea of the page, or "plot" is checked to see whether it was used in that DrawPass. If less than a quarter of the plots have been used recently (within kPlotRecentlyUsedCount iterations) and there are available plots in lower index pages, the higher index page will be deactivated, and its glyphs will gradually migrate to other pages via the usual upload system.

Garbage collection is initiated by the DrawAtlas's client via the compact() method.

  • Field Details

  • Constructor Details

    • DrawAtlas

      public DrawAtlas(int ct, int width, int height, int plotWidth, int plotHeight, @Nonnull DrawAtlas.AtlasGenerationCounter generationCounter, boolean useMultiPages, boolean useStorageTextures, String label)
  • Method Details

    • make

      @Nonnull public static DrawAtlas make(int ct, int width, int height, int plotWidth, int plotHeight, @Nonnull DrawAtlas.AtlasGenerationCounter generationCounter, boolean useMultiPages, boolean useStorageTextures, DrawAtlas.PlotEvictionCallback evictor, String label)
      Creates a DrawAtlas.
      Parameters:
      ct - The colorType which this atlas will store.
      width - Width in pixels of the atlas.
      height - Height in pixels of the atlas.
      plotWidth - The width of each plot. width/plotWidth should be an integer.
      plotHeight - The height of each plot. height/plotHeight should be an integer.
      generationCounter - A pointer to the context's generation counter.
      useMultiPages - Can the atlas use more than one texture.
      useStorageTextures - Should the atlas use storage textures.
      evictor - A pointer to an eviction callback class.
      label - Label for texture resources.
    • close

      public void close()
      Specified by:
      close in interface AutoCloseable
    • addRect

      public int addRect(@Nonnull RecordingContext context, int width, int height, @Nonnull DrawAtlas.AtlasLocator atlasLocator)
      Adds a width x height sub-image to the atlas. Upon success, it returns RESULT_SUCCESS and returns the plot location and the sub-image's coordinates in the backing texture. RESULT_TRY_AGAIN is returned if the sub-image cannot fit in the atlas without overwriting texels that will be read in the current list of draws. This indicates that the GraniteDevice should end its current draw, snap a DrawPass, and begin another before adding more data. RESULT_FAILURE will be returned when some unrecoverable error was encountered while trying to add the sub-image. In this case the draw being created should be discarded.

      This tracking does not generate UploadTasks per se. Instead, when the RenderPassTask is ready to be snapped, recordUploads(icyllis.arc3d.engine.RecordingContext, icyllis.arc3d.granite.SurfaceDrawContext) will be called by the GraniteDevice and that will generate the necessary UploadTasks.

      NOTE: When a draw that reads from the atlas is added to the DrawList, the client using this DrawAtlas must immediately call 'setLastUseToken' with the currentToken from the Recorder, otherwise the next call to addToAtlas might cause the previous data to be overwritten before it has been read.

    • getDataAt

      public long getDataAt(@Nonnull DrawAtlas.AtlasLocator atlasLocator)
      Returns the pointer to the plot data at the given position. The row bytes of the dst is bpp * plotWidth in the constructor. This must be called and can only be called once after addRect(RecordingContext, int, int, AtlasLocator) to update the data.
    • addToAtlas

      public int addToAtlas(@Nonnull RecordingContext context, int width, int height, Object imageBase, long imageAddr, @Nonnull DrawAtlas.AtlasLocator atlasLocator)
      This is a combination of addRect(RecordingContext, int, int, AtlasLocator), and copy the existing data to getDataAt(AtlasLocator) if success.
    • recordUploads

      public boolean recordUploads(RecordingContext context, SurfaceDrawContext sdc)
    • getTexture

      @RawPtr public @RawPtr ImageViewProxy getTexture(int pageIndex)
    • getAtlasGeneration

      public long getAtlasGeneration()
    • getNumActivePages

      public int getNumActivePages()
    • getNumPlots

      public int getNumPlots()
    • getMaxPages

      public int getMaxPages()
    • getPlotWidth

      public int getPlotWidth()
    • getPlotHeight

      public int getPlotHeight()
    • contains

      public boolean contains(@Nonnull DrawAtlas.PlotLocator plotLocator)
    • setLastUseToken

      public void setLastUseToken(@Nonnull DrawAtlas.AtlasLocator atlasLocator, long token)
    • setLastUseTokenBulk

      public void setLastUseTokenBulk(@Nonnull DrawAtlas.PlotBulkUseUpdater updater, long token)
    • compact

      public void compact(long startTokenForNextFlush)
    • purge

      public void purge(long startTokenForNextFlush)
    • evictAllPlots

      public void evictAllPlots()