Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/java2d/marlin/MarlinTileGenerator.java
38918 views
/*1* Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.marlin;2627import sun.java2d.pipe.AATileGenerator;28import sun.misc.Unsafe;2930final class MarlinTileGenerator implements AATileGenerator, MarlinConst {3132private static final int MAX_TILE_ALPHA_SUM = TILE_SIZE * TILE_SIZE33* MAX_AA_ALPHA;3435private final Renderer rdr;36private final MarlinCache cache;37private int x, y;3839MarlinTileGenerator(Renderer r) {40this.rdr = r;41this.cache = r.cache;42}4344MarlinTileGenerator init() {45this.x = cache.bboxX0;46this.y = cache.bboxY0;4748return this; // fluent API49}5051/**52* Disposes this tile generator:53* clean up before reusing this instance54*/55@Override56public void dispose() {57if (doMonitors) {58// called from AAShapePipe.renderTiles() (render tiles end):59RendererContext.stats.mon_pipe_renderTiles.stop();60}61// dispose cache:62cache.dispose();63// dispose renderer:64rdr.dispose();65// recycle the RendererContext instance66MarlinRenderingEngine.returnRendererContext(rdr.rdrCtx);67}6869void getBbox(int bbox[]) {70bbox[0] = cache.bboxX0;71bbox[1] = cache.bboxY0;72bbox[2] = cache.bboxX1;73bbox[3] = cache.bboxY1;74}7576/**77* Gets the width of the tiles that the generator batches output into.78* @return the width of the standard alpha tile79*/80@Override81public int getTileWidth() {82if (doMonitors) {83// called from AAShapePipe.renderTiles() (render tiles start):84RendererContext.stats.mon_pipe_renderTiles.start();85}86return TILE_SIZE;87}8889/**90* Gets the height of the tiles that the generator batches output into.91* @return the height of the standard alpha tile92*/93@Override94public int getTileHeight() {95return TILE_SIZE;96}9798/**99* Gets the typical alpha value that will characterize the current100* tile.101* The answer may be 0x00 to indicate that the current tile has102* no coverage in any of its pixels, or it may be 0xff to indicate103* that the current tile is completely covered by the path, or any104* other value to indicate non-trivial coverage cases.105* @return 0x00 for no coverage, 0xff for total coverage, or any other106* value for partial coverage of the tile107*/108@Override109public int getTypicalAlpha() {110int al = cache.alphaSumInTile(x);111// Note: if we have a filled rectangle that doesn't end on a tile112// border, we could still return 0xff, even though al!=maxTileAlphaSum113// This is because if we return 0xff, our users will fill a rectangle114// starting at x,y that has width = Math.min(TILE_SIZE, bboxX1-x),115// and height min(TILE_SIZE,bboxY1-y), which is what should happen.116// However, to support this, we would have to use 2 Math.min's117// and 2 multiplications per tile, instead of just 2 multiplications118// to compute maxTileAlphaSum. The savings offered would probably119// not be worth it, considering how rare this case is.120// Note: I have not tested this, so in the future if it is determined121// that it is worth it, it should be implemented. Perhaps this method's122// interface should be changed to take arguments the width and height123// of the current tile. This would eliminate the 2 Math.min calls that124// would be needed here, since our caller needs to compute these 2125// values anyway.126final int alpha = (al == 0x00 ? 0x00127: (al == MAX_TILE_ALPHA_SUM ? 0xff : 0x80));128if (doStats) {129RendererContext.stats.hist_tile_generator_alpha.add(alpha);130}131return alpha;132}133134/**135* Skips the current tile and moves on to the next tile.136* Either this method, or the getAlpha() method should be called137* once per tile, but not both.138*/139@Override140public void nextTile() {141if ((x += TILE_SIZE) >= cache.bboxX1) {142x = cache.bboxX0;143y += TILE_SIZE;144145if (y < cache.bboxY1) {146// compute for the tile line147// [ y; max(y + TILE_SIZE, bboxY1) ]148this.rdr.endRendering(y);149}150}151}152153/**154* Gets the alpha coverage values for the current tile.155* Either this method, or the nextTile() method should be called156* once per tile, but not both.157*/158@Override159public void getAlpha(final byte tile[], final int offset,160final int rowstride)161{162if (cache.useRLE) {163getAlphaRLE(tile, offset, rowstride);164} else {165getAlphaNoRLE(tile, offset, rowstride);166}167}168169/**170* Gets the alpha coverage values for the current tile.171* Either this method, or the nextTile() method should be called172* once per tile, but not both.173*/174private void getAlphaNoRLE(final byte tile[], final int offset,175final int rowstride)176{177if (doMonitors) {178RendererContext.stats.mon_ptg_getAlpha.start();179}180181// local vars for performance:182final MarlinCache _cache = this.cache;183final long[] rowAAChunkIndex = _cache.rowAAChunkIndex;184final int[] rowAAx0 = _cache.rowAAx0;185final int[] rowAAx1 = _cache.rowAAx1;186187final int x0 = this.x;188final int x1 = FloatMath.min(x0 + TILE_SIZE, _cache.bboxX1);189190// note: process tile line [0 - 32[191final int y0 = 0;192final int y1 = FloatMath.min(this.y + TILE_SIZE, _cache.bboxY1) - this.y;193194if (doLogBounds) {195MarlinUtils.logInfo("getAlpha = [" + x0 + " ... " + x1196+ "[ [" + y0 + " ... " + y1 + "[");197}198199final Unsafe _unsafe = OffHeapArray.unsafe;200final long SIZE = 1L;201final long addr_rowAA = _cache.rowAAChunk.address;202long addr;203204final int skipRowPixels = (rowstride - (x1 - x0));205206int aax0, aax1, end;207int idx = offset;208209for (int cy = y0, cx; cy < y1; cy++) {210// empty line (default)211cx = x0;212213aax1 = rowAAx1[cy]; // exclusive214215// quick check if there is AA data216// corresponding to this tile [x0; x1[217if (aax1 > x0) {218aax0 = rowAAx0[cy]; // inclusive219220if (aax0 < x1) {221// note: cx is the cursor pointer in the tile array222// (left to right)223cx = aax0;224225// ensure cx >= x0226if (cx <= x0) {227cx = x0;228} else {229// fill line start until first AA pixel rowAA exclusive:230for (end = x0; end < cx; end++) {231tile[idx++] = 0;232}233}234235// now: cx >= x0 but cx < aax0 (x1 < aax0)236237// Copy AA data (sum alpha data):238addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);239240for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) {241// cx inside tile[x0; x1[ :242tile[idx++] = _unsafe.getByte(addr); // [0..255]243addr += SIZE;244}245}246}247248// fill line end249while (cx < x1) {250tile[idx++] = 0;251cx++;252}253254if (doTrace) {255for (int i = idx - (x1 - x0); i < idx; i++) {256System.out.print(hex(tile[i], 2));257}258System.out.println();259}260261idx += skipRowPixels;262}263264nextTile();265266if (doMonitors) {267RendererContext.stats.mon_ptg_getAlpha.stop();268}269}270271/**272* Gets the alpha coverage values for the current tile.273* Either this method, or the nextTile() method should be called274* once per tile, but not both.275*/276private void getAlphaRLE(final byte tile[], final int offset,277final int rowstride)278{279if (doMonitors) {280RendererContext.stats.mon_ptg_getAlpha.start();281}282283// Decode run-length encoded alpha mask data284// The data for row j begins at cache.rowOffsetsRLE[j]285// and is encoded as a set of 2-byte pairs (val, runLen)286// terminated by a (0, 0) pair.287288// local vars for performance:289final MarlinCache _cache = this.cache;290final long[] rowAAChunkIndex = _cache.rowAAChunkIndex;291final int[] rowAAx0 = _cache.rowAAx0;292final int[] rowAAx1 = _cache.rowAAx1;293final int[] rowAAEnc = _cache.rowAAEnc;294final long[] rowAALen = _cache.rowAALen;295final long[] rowAAPos = _cache.rowAAPos;296297final int x0 = this.x;298final int x1 = FloatMath.min(x0 + TILE_SIZE, _cache.bboxX1);299300// note: process tile line [0 - 32[301final int y0 = 0;302final int y1 = FloatMath.min(this.y + TILE_SIZE, _cache.bboxY1) - this.y;303304if (doLogBounds) {305MarlinUtils.logInfo("getAlpha = [" + x0 + " ... " + x1306+ "[ [" + y0 + " ... " + y1 + "[");307}308309final Unsafe _unsafe = OffHeapArray.unsafe;310final long SIZE_BYTE = 1L;311final long SIZE_INT = 4L;312final long addr_rowAA = _cache.rowAAChunk.address;313long addr, addr_row, last_addr, addr_end;314315final int skipRowPixels = (rowstride - (x1 - x0));316317int cx, cy, cx1;318int rx0, rx1, runLen, end;319int packed;320byte val;321int idx = offset;322323for (cy = y0; cy < y1; cy++) {324// empty line (default)325cx = x0;326327if (rowAAEnc[cy] == 0) {328// Raw encoding:329330final int aax1 = rowAAx1[cy]; // exclusive331332// quick check if there is AA data333// corresponding to this tile [x0; x1[334if (aax1 > x0) {335final int aax0 = rowAAx0[cy]; // inclusive336337if (aax0 < x1) {338// note: cx is the cursor pointer in the tile array339// (left to right)340cx = aax0;341342// ensure cx >= x0343if (cx <= x0) {344cx = x0;345} else {346// fill line start until first AA pixel rowAA exclusive:347for (end = x0; end < cx; end++) {348tile[idx++] = 0;349}350}351352// now: cx >= x0 but cx < aax0 (x1 < aax0)353354// Copy AA data (sum alpha data):355addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);356357for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) {358tile[idx++] = _unsafe.getByte(addr); // [0..255]359addr += SIZE_BYTE;360}361}362}363} else {364// RLE encoding:365366// quick check if there is AA data367// corresponding to this tile [x0; x1[368if (rowAAx1[cy] > x0) { // last pixel exclusive369370cx = rowAAx0[cy]; // inclusive371if (cx > x1) {372cx = x1;373}374375// fill line start until first AA pixel rowAA exclusive:376for (int i = x0; i < cx; i++) {377tile[idx++] = 0;378}379380// get row address:381addr_row = addr_rowAA + rowAAChunkIndex[cy];382// get row end address:383addr_end = addr_row + rowAALen[cy]; // coded length384385// reuse previous iteration position:386addr = addr_row + rowAAPos[cy];387388last_addr = 0L;389390while ((cx < x1) && (addr < addr_end)) {391// keep current position:392last_addr = addr;393394// packed value:395packed = _unsafe.getInt(addr);396397// last exclusive pixel x-coordinate:398cx1 = (packed >> 8);399// as bytes:400addr += SIZE_INT;401402rx0 = cx;403if (rx0 < x0) {404rx0 = x0;405}406rx1 = cx = cx1;407if (rx1 > x1) {408rx1 = x1;409cx = x1; // fix last x410}411// adjust runLen:412runLen = rx1 - rx0;413414// ensure rx1 > rx0:415if (runLen > 0) {416val = (byte)(packed & 0xFF); // [0..255]417418do {419tile[idx++] = val;420} while (--runLen > 0);421}422}423424// Update last position in RLE entries:425if (last_addr != 0L) {426// Fix x0:427rowAAx0[cy] = cx; // inclusive428// Fix position:429rowAAPos[cy] = (last_addr - addr_row);430}431}432}433434// fill line end435while (cx < x1) {436tile[idx++] = 0;437cx++;438}439440if (doTrace) {441for (int i = idx - (x1 - x0); i < idx; i++) {442System.out.print(hex(tile[i], 2));443}444System.out.println();445}446447idx += skipRowPixels;448}449450nextTile();451452if (doMonitors) {453RendererContext.stats.mon_ptg_getAlpha.stop();454}455}456457static String hex(int v, int d) {458String s = Integer.toHexString(v);459while (s.length() < d) {460s = "0" + s;461}462return s.substring(0, d);463}464}465466467