Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.m
66646 views
/*1* Copyright (c) 2019, 2021, 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*/2425#include <stdlib.h>26#include <string.h>2728#include "sun_java2d_SunGraphics2D.h"2930#include "MTLPaints.h"31#include "MTLVertexCache.h"32#include "MTLTexturePool.h"33#include "MTLTextRenderer.h"34#include "common.h"3536typedef struct _J2DVertex {37float position[2];38float txtpos[2];39} J2DVertex;4041static J2DVertex *vertexCache = NULL;42static jint vertexCacheIndex = 0;4344static MTLPooledTextureHandle * maskCacheTex = NULL;45static jint maskCacheIndex = 0;46static id<MTLRenderCommandEncoder> encoder = NULL;4748#define MTLVC_ADD_VERTEX(TX, TY, DX, DY, DZ) \49do { \50J2DVertex *v = &vertexCache[vertexCacheIndex++]; \51v->txtpos[0] = TX; \52v->txtpos[1] = TY; \53v->position[0]= DX; \54v->position[1] = DY; \55} while (0)5657#define MTLVC_ADD_TRIANGLES(TX1, TY1, TX2, TY2, DX1, DY1, DX2, DY2) \58do { \59MTLVC_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \60MTLVC_ADD_VERTEX(TX2, TY1, DX2, DY1, 0); \61MTLVC_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \62MTLVC_ADD_VERTEX(TX2, TY2, DX2, DY2, 0); \63MTLVC_ADD_VERTEX(TX1, TY2, DX1, DY2, 0); \64MTLVC_ADD_VERTEX(TX1, TY1, DX1, DY1, 0); \65} while (0)6667// Next define should exactly match to the amount68// of MTLVC_ADD_VERTEX in MTLVC_ADD_TRIANGLES69#define VERTS_FOR_A_QUAD 67071jboolean72MTLVertexCache_InitVertexCache()73{74J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitVertexCache");7576if (vertexCache == NULL) {77J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitVertexCache : vertexCache == NULL");78vertexCache = (J2DVertex *)malloc(MTLVC_MAX_INDEX * sizeof(J2DVertex));79if (vertexCache == NULL) {80return JNI_FALSE;81}82}8384return JNI_TRUE;85}8687void88MTLVertexCache_FlushVertexCache(MTLContext *mtlc)89{90J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_FlushVertexCache");9192if (vertexCacheIndex > 0) {93[encoder setVertexBytes: vertexCache length:vertexCacheIndex * sizeof(J2DVertex)94atIndex:MeshVertexBuffer];9596[encoder setFragmentTexture:maskCacheTex.texture atIndex: 0];97J2dTraceLn1(J2D_TRACE_INFO,98"MTLVertexCache_FlushVertexCache : encode %d characters", (vertexCacheIndex / 6));99[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:vertexCacheIndex];100}101vertexCacheIndex = 0;102maskCacheIndex = 0;103104if (maskCacheTex != nil) {105[[mtlc getCommandBufferWrapper] registerPooledTexture:maskCacheTex];106[maskCacheTex release];107maskCacheTex = nil;108}109}110111void112MTLVertexCache_FlushGlyphVertexCache()113{114J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_FlushGlyphVertexCache");115116if (vertexCacheIndex > 0) {117[encoder setVertexBytes: vertexCache length:vertexCacheIndex * sizeof(J2DVertex)118atIndex:MeshVertexBuffer];119id<MTLTexture> glyphCacheTex = MTLTR_GetGlyphCacheTexture();120[encoder setFragmentTexture:glyphCacheTex atIndex: 0];121J2dTraceLn1(J2D_TRACE_INFO,122"MTLVertexCache_FlushGlyphVertexCache : encode %d characters", (vertexCacheIndex / 6));123[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:vertexCacheIndex];124}125vertexCacheIndex = 0;126}127128void MTLVertexCache_FreeVertexCache()129{130free(vertexCache);131vertexCache = NULL;132}133134static jboolean135MTLVertexCache_InitMaskCache(MTLContext *mtlc) {136J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_InitMaskCache");137if (maskCacheTex == NULL) {138maskCacheTex = [mtlc.texturePool getTexture:MTLVC_MASK_CACHE_WIDTH_IN_TEXELS139height:MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS140format:MTLPixelFormatA8Unorm];141[maskCacheTex retain];142if (maskCacheTex == nil) {143J2dTraceLn(J2D_TRACE_ERROR, "MTLVertexCache_InitMaskCache: can't obtain temporary texture object from pool");144return JNI_FALSE;145}146}147// init special fully opaque tile in the upper-right corner of148// the mask cache texture149150char tile[MTLVC_MASK_CACHE_TILE_SIZE];151memset(tile, 0xff, MTLVC_MASK_CACHE_TILE_SIZE);152153jint texx = MTLVC_MASK_CACHE_TILE_WIDTH * (MTLVC_MASK_CACHE_WIDTH_IN_TILES - 1);154155jint texy = MTLVC_MASK_CACHE_TILE_HEIGHT * (MTLVC_MASK_CACHE_HEIGHT_IN_TILES - 1);156157NSUInteger bytesPerRow = 1 * MTLVC_MASK_CACHE_TILE_WIDTH;158159MTLRegion region = {160{texx, texy, 0},161{MTLVC_MASK_CACHE_TILE_WIDTH, MTLVC_MASK_CACHE_TILE_HEIGHT, 1}162};163164165// do we really need this??166[maskCacheTex.texture replaceRegion:region167mipmapLevel:0168withBytes:tile169bytesPerRow:bytesPerRow];170171return JNI_TRUE;172}173174void175MTLVertexCache_EnableMaskCache(MTLContext *mtlc, BMTLSDOps *dstOps)176{177J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_EnableMaskCache");178179if (!MTLVertexCache_InitVertexCache()) {180return;181}182183if (maskCacheTex == NULL) {184if (!MTLVertexCache_InitMaskCache(mtlc)) {185return;186}187}188MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps);189}190191void192MTLVertexCache_DisableMaskCache(MTLContext *mtlc)193{194// TODO : Once we enable check_previous_op195// we will start using DisableMaskCache until then196// we are force flushing vertexcache.197J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_DisableMaskCache");198MTLVertexCache_FlushVertexCache(mtlc);199maskCacheIndex = 0;200free(vertexCache);201vertexCache = NULL;202}203204void205MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps) {206J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_CreateSamplingEncoder");207encoder = [mtlc.encoderManager getTextEncoder:dstOps208isSrcOpaque:NO];209}210211void212MTLVertexCache_AddMaskQuad(MTLContext *mtlc,213jint srcx, jint srcy,214jint dstx, jint dsty,215jint width, jint height,216jint maskscan, void *mask,217BMTLSDOps *dstOps)218{219jfloat tx1, ty1, tx2, ty2;220jfloat dx1, dy1, dx2, dy2;221222J2dTraceLn1(J2D_TRACE_INFO, "MTLVertexCache_AddMaskQuad: %d",223maskCacheIndex);224225// MTLVC_ADD_TRIANGLES at the end of this function226// will place VERTS_FOR_A_QUAD vertexes to the vertex cache227// check free space and flush if needed.228if ((maskCacheIndex >= MTLVC_MASK_CACHE_MAX_INDEX) ||229((vertexCacheIndex + VERTS_FOR_A_QUAD) >= MTLVC_MAX_INDEX))230{231J2dTraceLn2(J2D_TRACE_INFO, "maskCacheIndex = %d, vertexCacheIndex = %d", maskCacheIndex, vertexCacheIndex);232MTLVertexCache_FlushVertexCache(mtlc);233MTLVertexCache_EnableMaskCache(mtlc, dstOps);234maskCacheIndex = 0;235}236237if (mask != NULL) {238jint texx = MTLVC_MASK_CACHE_TILE_WIDTH *239(maskCacheIndex % MTLVC_MASK_CACHE_WIDTH_IN_TILES);240jint texy = MTLVC_MASK_CACHE_TILE_HEIGHT *241(maskCacheIndex / MTLVC_MASK_CACHE_WIDTH_IN_TILES);242J2dTraceLn5(J2D_TRACE_INFO, "texx = %d texy = %d width = %d height = %d maskscan = %d", texx, texy, width,243height, maskscan);244NSUInteger bytesPerRow = 1 * width;245NSUInteger slice = bytesPerRow * srcy + srcx;246MTLRegion region = {247{texx, texy, 0},248{width, height, 1}249};250251// Whenever we have source stride bigger that destination stride252// we need to pick appropriate source subtexture. In repalceRegion253// we can give destination subtexturing properly but we can't254// subtexture from system memory glyph we have. So in such255// cases we are creating seperate tile and scan the source256// stride into destination using memcpy. In case of OpenGL we257// can update source pointers, in case of D3D we ar doing memcpy.258// We can use MTLBuffer and then copy source subtexture but that259// adds extra blitting logic.260// TODO : Research more and try removing memcpy logic.261if (maskscan <= width) {262int height_offset = bytesPerRow * srcy;263[maskCacheTex.texture replaceRegion:region264mipmapLevel:0265withBytes:mask + height_offset266bytesPerRow:bytesPerRow];267} else {268int dst_offset, src_offset;269int size = 1 * width * height;270char tile[size];271dst_offset = 0;272for (int i = srcy; i < srcy + height; i++) {273J2dTraceLn2(J2D_TRACE_INFO, "srcx = %d srcy = %d", srcx, srcy);274src_offset = maskscan * i + srcx;275J2dTraceLn2(J2D_TRACE_INFO, "src_offset = %d dst_offset = %d", src_offset, dst_offset);276memcpy(tile + dst_offset, mask + src_offset, width);277dst_offset = dst_offset + width;278}279[maskCacheTex.texture replaceRegion:region280mipmapLevel:0281withBytes:tile282bytesPerRow:bytesPerRow];283}284285tx1 = ((jfloat) texx) / MTLVC_MASK_CACHE_WIDTH_IN_TEXELS;286ty1 = ((jfloat) texy) / MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS;287} else {288tx1 = ((jfloat)MTLVC_MASK_CACHE_SPECIAL_TILE_X) /289MTLVC_MASK_CACHE_WIDTH_IN_TEXELS;290ty1 = ((jfloat)MTLVC_MASK_CACHE_SPECIAL_TILE_Y) /291MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS;292}293maskCacheIndex++;294295tx2 = tx1 + (((jfloat)width) / MTLVC_MASK_CACHE_WIDTH_IN_TEXELS);296ty2 = ty1 + (((jfloat)height) / MTLVC_MASK_CACHE_HEIGHT_IN_TEXELS);297298dx1 = (jfloat)dstx;299dy1 = (jfloat)dsty;300dx2 = dx1 + width;301dy2 = dy1 + height;302303J2dTraceLn8(J2D_TRACE_INFO, "tx1 = %f ty1 = %f tx2 = %f ty2 = %f dx1 = %f dy1 = %f dx2 = %f dy2 = %f", tx1, ty1, tx2, ty2, dx1, dy1, dx2, dy2);304MTLVC_ADD_TRIANGLES(tx1, ty1, tx2, ty2,305dx1, dy1, dx2, dy2);306}307308void309MTLVertexCache_AddGlyphQuad(MTLContext *mtlc,310jfloat tx1, jfloat ty1, jfloat tx2, jfloat ty2,311jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2)312{313J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_AddGlyphQuad");314315// MTLVC_ADD_TRIANGLES adds VERTS_FOR_A_QUAD vertexes into Cache316// so need to check space for VERTS_FOR_A_QUAD elements317if ((vertexCacheIndex + VERTS_FOR_A_QUAD) >= MTLVC_MAX_INDEX)318{319J2dTraceLn2(J2D_TRACE_INFO, "maskCacheIndex = %d, vertexCacheIndex = %d", maskCacheIndex, vertexCacheIndex);320MTLVertexCache_FlushGlyphVertexCache();321}322323MTLVC_ADD_TRIANGLES(tx1, ty1, tx2, ty2,324dx1, dy1, dx2, dy2);325}326327328