Path: blob/master/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLGlyphCache.m
41159 views
/*1* Copyright (c) 2020, 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 "jni.h"27#include "MTLGlyphCache.h"28#include "Trace.h"2930/**31* When the cache is full, we will try to reuse the cache cells that have32* been used relatively less than the others (and we will save the cells that33* have been rendered more than the threshold defined here).34*/35#define TIMES_RENDERED_THRESHOLD 53637/**38* Creates a new GlyphCacheInfo structure, fills in the initial values, and39* then returns a pointer to the GlyphCacheInfo record.40*41* Note that this method only sets up a data structure describing a42* rectangular region of accelerated memory, containing "virtual" cells of43* the requested size. The cell information is added lazily to the linked44* list describing the cache as new glyphs are added. Platform specific45* glyph caching code is responsible for actually creating the accelerated46* memory surface that will contain the individual glyph images.47*48* Each glyph contains a reference to a list of cell infos - one per glyph49* cache. There may be multiple glyph caches (for example, one per graphics50* adapter), so if the glyph is cached on two devices its cell list will51* consists of two elements corresponding to different glyph caches.52*53* The platform-specific glyph caching code is supposed to use54* GetCellInfoForCache method for retrieving cache infos from the glyph's list.55*56* Note that if it is guaranteed that there will be only one global glyph57* cache then it one does not have to use AccelGlyphCache_GetCellInfoForCache58* for retrieving cell info for the glyph, but instead just use the struct's59* field directly.60*/61MTLGlyphCacheInfo *62MTLGlyphCache_Init(jint width, jint height,63jint cellWidth, jint cellHeight,64MTLFlushFunc *func)65{66MTLGlyphCacheInfo *gcinfo;6768J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Init");6970gcinfo = (MTLGlyphCacheInfo *)malloc(sizeof(MTLGlyphCacheInfo));71if (gcinfo == NULL) {72J2dRlsTraceLn(J2D_TRACE_ERROR,73"MTLGlyphCache_Init: could not allocate MTLGlyphCacheInfo");74return NULL;75}7677gcinfo->head = NULL;78gcinfo->tail = NULL;79gcinfo->width = width;80gcinfo->height = height;81gcinfo->cellWidth = cellWidth;82gcinfo->cellHeight = cellHeight;83gcinfo->Flush = func;8485return gcinfo;86}8788/**89* Attempts to add the provided glyph to the specified cache. If the90* operation is successful, a pointer to the newly occupied cache cell is91* stored in the glyph's cellInfo field; otherwise, its cellInfo field is92* set to NULL, indicating that the glyph's original bits should be rendered93* instead. If the cache is full, the least-recently-used glyph is94* invalidated and its cache cell is reassigned to the new glyph being added.95*96* Note that this method only ensures that a rectangular region in the97* "virtual" glyph cache is available for the glyph image. Platform specific98* glyph caching code is responsible for actually caching the glyph image99* in the associated accelerated memory surface.100*101* Returns created cell info if it was successfully created and added to the102* cache and glyph's cell lists, NULL otherwise.103*/104MTLCacheCellInfo *105MTLGlyphCache_AddGlyph(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)106{107MTLCacheCellInfo *cellinfo = NULL;108jint w = glyph->width;109jint h = glyph->height;110111J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_AddGlyph");112113if ((glyph->width > cache->cellWidth) ||114(glyph->height > cache->cellHeight))115{116return NULL;117}118119jint x, y;120121if (cache->head == NULL) {122x = 0;123y = 0;124} else {125x = cache->tail->x + cache->cellWidth;126y = cache->tail->y;127if ((x + cache->cellWidth) > cache->width) {128x = 0;129y += cache->cellHeight;130}131}132133// create new CacheCellInfo134cellinfo = (MTLCacheCellInfo *)malloc(sizeof(MTLCacheCellInfo));135if (cellinfo == NULL) {136J2dTraceLn(J2D_TRACE_ERROR, "could not allocate CellInfo");137return NULL;138}139140cellinfo->cacheInfo = cache;141cellinfo->glyphInfo = glyph;142cellinfo->timesRendered = 0;143cellinfo->x = x;144cellinfo->y = y;145cellinfo->leftOff = 0;146cellinfo->rightOff = 0;147cellinfo->tx1 = (jfloat)cellinfo->x / cache->width;148cellinfo->ty1 = (jfloat)cellinfo->y / cache->height;149cellinfo->tx2 = cellinfo->tx1 + ((jfloat)w / cache->width);150cellinfo->ty2 = cellinfo->ty1 + ((jfloat)h / cache->height);151152if (cache->head == NULL) {153// initialize the head cell154cache->head = cellinfo;155} else {156// update existing tail cell157cache->tail->next = cellinfo;158}159160// add the new cell to the end of the list161cache->tail = cellinfo;162cellinfo->next = NULL;163cellinfo->nextGCI = NULL;164165// add cache cell to the glyph's cells list166MTLGlyphCache_AddCellInfo(glyph, cellinfo);167return cellinfo;168}169170171bool172MTLGlyphCache_IsCacheFull(MTLGlyphCacheInfo *cache, GlyphInfo *glyph)173{174jint w = glyph->width;175jint h = glyph->height;176177J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_IsCacheFull");178179jint x, y;180181if (cache->head == NULL) {182return JNI_FALSE;183} else {184x = cache->tail->x + cache->cellWidth;185y = cache->tail->y;186if ((x + cache->cellWidth) > cache->width) {187x = 0;188y += cache->cellHeight;189if ((y + cache->cellHeight) > cache->height) {190return JNI_TRUE;191}192}193}194return JNI_FALSE;195}196/**197* Invalidates all cells in the cache. Note that this method does not198* attempt to compact the cache in any way; it just invalidates any cells199* that already exist.200*/201void202MTLGlyphCache_Invalidate(MTLGlyphCacheInfo *cache)203{204MTLCacheCellInfo *cellinfo;205206J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Invalidate");207208if (cache == NULL) {209return;210}211212// flush any pending vertices that may be depending on the current213// glyph cache layout214if (cache->Flush != NULL) {215cache->Flush();216}217218cellinfo = cache->head;219while (cellinfo != NULL) {220if (cellinfo->glyphInfo != NULL) {221// if the cell is occupied, notify the base glyph that its222// cached version for this cache is about to be invalidated223MTLGlyphCache_RemoveCellInfo(cellinfo->glyphInfo, cellinfo);224}225cellinfo = cellinfo->next;226}227}228229/**230* Invalidates and frees all cells and the cache itself. The "cache" pointer231* becomes invalid after this function returns.232*/233void234MTLGlyphCache_Free(MTLGlyphCacheInfo *cache)235{236MTLCacheCellInfo *cellinfo;237238J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_Free");239240if (cache == NULL) {241return;242}243244// flush any pending vertices that may be depending on the current245// glyph cache246if (cache->Flush != NULL) {247cache->Flush();248}249250while (cache->head != NULL) {251cellinfo = cache->head;252if (cellinfo->glyphInfo != NULL) {253// if the cell is occupied, notify the base glyph that its254// cached version for this cache is about to be invalidated255MTLGlyphCache_RemoveCellInfo(cellinfo->glyphInfo, cellinfo);256}257cache->head = cellinfo->next;258free(cellinfo);259}260free(cache);261}262263/**264* Add cell info to the head of the glyph's list of cached cells.265*/266void267MTLGlyphCache_AddCellInfo(GlyphInfo *glyph, MTLCacheCellInfo *cellInfo)268{269// assert (glyph != NULL && cellInfo != NULL)270J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_AddCellInfo");271J2dTraceLn2(J2D_TRACE_VERBOSE, " glyph 0x%x: adding cell 0x%x to the list",272glyph, cellInfo);273274cellInfo->glyphInfo = glyph;275cellInfo->nextGCI = glyph->cellInfo;276glyph->cellInfo = cellInfo;277glyph->managed = MANAGED_GLYPH;278}279280/**281* Removes cell info from the glyph's list of cached cells.282*/283void284MTLGlyphCache_RemoveCellInfo(GlyphInfo *glyph, MTLCacheCellInfo *cellInfo)285{286MTLCacheCellInfo *currCellInfo = glyph->cellInfo;287MTLCacheCellInfo *prevInfo = NULL;288// assert (glyph!= NULL && glyph->cellInfo != NULL && cellInfo != NULL)289J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_RemoveCellInfo");290do {291if (currCellInfo == cellInfo) {292J2dTraceLn2(J2D_TRACE_VERBOSE,293" glyph 0x%x: removing cell 0x%x from glyph's list",294glyph, currCellInfo);295if (prevInfo == NULL) { // it's the head, chop-chop296glyph->cellInfo = currCellInfo->nextGCI;297} else {298prevInfo->nextGCI = currCellInfo->nextGCI;299}300currCellInfo->glyphInfo = NULL;301currCellInfo->nextGCI = NULL;302return;303}304prevInfo = currCellInfo;305currCellInfo = currCellInfo->nextGCI;306} while (currCellInfo != NULL);307J2dTraceLn2(J2D_TRACE_WARNING, "MTLGlyphCache_RemoveCellInfo: "\308"no cell 0x%x in glyph 0x%x's cell list",309cellInfo, glyph);310}311312/**313* Removes cell info from the glyph's list of cached cells.314*/315JNIEXPORT void316MTLGlyphCache_RemoveAllCellInfos(GlyphInfo *glyph)317{318MTLCacheCellInfo *currCell, *prevCell;319320J2dTraceLn(J2D_TRACE_INFO, "MTLGlyphCache_RemoveAllCellInfos");321322if (glyph == NULL || glyph->cellInfo == NULL) {323return;324}325326// invalidate all of this glyph's accelerated cache cells327currCell = glyph->cellInfo;328do {329currCell->glyphInfo = NULL;330prevCell = currCell;331currCell = currCell->nextGCI;332prevCell->nextGCI = NULL;333} while (currCell != NULL);334335glyph->cellInfo = NULL;336}337338/**339* Returns cell info associated with particular cache from the glyph's list of340* cached cells.341*/342MTLCacheCellInfo *343MTLGlyphCache_GetCellInfoForCache(GlyphInfo *glyph, MTLGlyphCacheInfo *cache)344{345// assert (glyph != NULL && cache != NULL)346J2dTraceLn(J2D_TRACE_VERBOSE2, "MTLGlyphCache_GetCellInfoForCache");347348if (glyph->cellInfo != NULL) {349MTLCacheCellInfo *cellInfo = glyph->cellInfo;350do {351if (cellInfo->cacheInfo == cache) {352J2dTraceLn3(J2D_TRACE_VERBOSE2,353" glyph 0x%x: found cell 0x%x for cache 0x%x",354glyph, cellInfo, cache);355return cellInfo;356}357cellInfo = cellInfo->nextGCI;358} while (cellInfo != NULL);359}360J2dTraceLn2(J2D_TRACE_VERBOSE2, " glyph 0x%x: no cell for cache 0x%x",361glyph, cache);362return NULL;363}364365366