blob: b88d60957f395fbb4fc9cd005d61acbf24c4fdb7 [file]
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdlib.h>
#include "sun_java2d_SunGraphics2D.h"
#include "jlong.h"
#import "MTLContext.h"
#include "MTLRenderQueue.h"
#import "MTLSamplerManager.h"
#import "MTLStencilManager.h"
extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
static struct TxtVertex verts[PGRAM_VERTEX_COUNT] = {
{{-1.0, 1.0}, {0.0, 0.0}},
{{1.0, 1.0}, {1.0, 0.0}},
{{1.0, -1.0}, {1.0, 1.0}},
{{1.0, -1.0}, {1.0, 1.0}},
{{-1.0, -1.0}, {0.0, 1.0}},
{{-1.0, 1.0}, {0.0, 0.0}}
};
MTLTransform* tempTransform = nil;
@implementation MTLCommandBufferWrapper {
id<MTLCommandBuffer> _commandBuffer;
NSMutableArray * _pooledTextures;
NSLock* _lock;
}
- (id) initWithCommandBuffer:(id<MTLCommandBuffer>)cmdBuf {
self = [super init];
if (self) {
_commandBuffer = [cmdBuf retain];
_pooledTextures = [[NSMutableArray alloc] init];
_lock = [[NSLock alloc] init];
}
return self;
}
- (id<MTLCommandBuffer>) getCommandBuffer {
return _commandBuffer;
}
- (void) onComplete { // invoked from completion handler in some pooled thread
[_lock lock];
@try {
for (int c = 0; c < [_pooledTextures count]; ++c)
[[_pooledTextures objectAtIndex:c] releaseTexture];
[_pooledTextures removeAllObjects];
} @finally {
[_lock unlock];
}
}
- (void) registerPooledTexture:(MTLPooledTextureHandle *)handle {
[_lock lock];
@try {
[_pooledTextures addObject:handle];
} @finally {
[_lock unlock];
}
}
- (void) dealloc {
[self onComplete];
[_pooledTextures release];
_pooledTextures = nil;
[_commandBuffer release];
_commandBuffer = nil;
[_lock release];
_lock = nil;
[super dealloc];
}
@end
@implementation MTLContext {
MTLCommandBufferWrapper * _commandBufferWrapper;
MTLComposite * _composite;
MTLPaint * _paint;
MTLTransform * _transform;
MTLTransform * _tempTransform;
MTLClip * _clip;
NSObject* _bufImgOp; // TODO: pass as parameter of IsoBlit
EncoderManager * _encoderManager;
MTLSamplerManager * _samplerManager;
MTLStencilManager * _stencilManager;
}
@synthesize textureFunction,
vertexCacheEnabled, aaEnabled, device, pipelineStateStorage,
commandQueue, blitCommandQueue, vertexBuffer,
texturePool, paint=_paint, encoderManager=_encoderManager,
samplerManager=_samplerManager, stencilManager=_stencilManager;
extern void initSamplers(id<MTLDevice> device);
- (id)initWithDevice:(id<MTLDevice>)d shadersLib:(NSString*)shadersLib {
self = [super init];
if (self) {
// Initialization code here.
device = d;
pipelineStateStorage = [[MTLPipelineStatesStorage alloc] initWithDevice:device shaderLibPath:shadersLib];
if (pipelineStateStorage == nil) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext.initWithDevice(): Failed to initialize MTLPipelineStatesStorage.");
return nil;
}
texturePool = [[MTLTexturePool alloc] initWithDevice:device];
vertexBuffer = [device newBufferWithBytes:verts
length:sizeof(verts)
options:MTLResourceCPUCacheModeDefaultCache];
_encoderManager = [[EncoderManager alloc] init];
[_encoderManager setContext:self];
_samplerManager = [[MTLSamplerManager alloc] initWithDevice:device];
_stencilManager = [[MTLStencilManager alloc] initWithDevice:device];
_composite = [[MTLComposite alloc] init];
_paint = [[MTLPaint alloc] init];
_transform = [[MTLTransform alloc] init];
_clip = [[MTLClip alloc] init];
_bufImgOp = nil;
_commandBufferWrapper = nil;
// Create command queue
commandQueue = [device newCommandQueue];
blitCommandQueue = [device newCommandQueue];
_tempTransform = [[MTLTransform alloc] init];
}
return self;
}
- (void)dealloc {
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.dealloc");
// TODO : Check that texturePool is completely released.
// texturePool content is released in MTLCommandBufferWrapper.onComplete()
//self.texturePool = nil;
self.vertexBuffer = nil;
self.commandQueue = nil;
self.blitCommandQueue = nil;
self.pipelineStateStorage = nil;
if (_encoderManager != nil) {
[_encoderManager release];
_encoderManager = nil;
}
if (_samplerManager != nil) {
[_samplerManager release];
_samplerManager = nil;
}
if (_stencilManager != nil) {
[_stencilManager release];
_stencilManager = nil;
}
if (_composite != nil) {
[_composite release];
_composite = nil;
}
if (_paint != nil) {
[_paint release];
_paint = nil;
}
if (_transform != nil) {
[_transform release];
_transform = nil;
}
if (_tempTransform != nil) {
[_tempTransform release];
_tempTransform = nil;
}
if (_clip != nil) {
[_clip release];
_clip = nil;
}
[super dealloc];
}
- (void) reset {
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLContext : reset");
// Add code for context state reset here
}
- (MTLCommandBufferWrapper *) getCommandBufferWrapper {
if (_commandBufferWrapper == nil) {
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLContext : commandBuffer is NULL");
// NOTE: Command queues are thread-safe and allow multiple outstanding command buffers to be encoded simultaneously.
_commandBufferWrapper = [[MTLCommandBufferWrapper alloc] initWithCommandBuffer:[self.commandQueue commandBuffer]];// released in [layer blitTexture]
}
return _commandBufferWrapper;
}
- (MTLCommandBufferWrapper *) pullCommandBufferWrapper {
MTLCommandBufferWrapper * result = _commandBufferWrapper;
_commandBufferWrapper = nil;
return result;
}
+ (MTLContext*) setSurfacesEnv:(JNIEnv*)env src:(jlong)pSrc dst:(jlong)pDst {
BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrc);
BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDst);
MTLContext *mtlc = NULL;
if (srcOps == NULL || dstOps == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_SetSurfaces: ops are null");
return NULL;
}
J2dTraceLn6(J2D_TRACE_VERBOSE, "MTLContext_SetSurfaces: bsrc=%p (tex=%p type=%d), bdst=%p (tex=%p type=%d)", srcOps, srcOps->pTexture, srcOps->drawableType, dstOps, dstOps->pTexture, dstOps->drawableType);
if (dstOps->drawableType == MTLSD_TEXTURE) {
J2dRlsTraceLn(J2D_TRACE_ERROR,
"MTLContext_SetSurfaces: texture cannot be used as destination");
return NULL;
}
if (dstOps->drawableType == MTLSD_UNDEFINED) {
// initialize the surface as an MTLSD_WINDOW
if (!MTLSD_InitMTLWindow(env, dstOps)) {
J2dRlsTraceLn(J2D_TRACE_ERROR,
"MTLContext_SetSurfaces: could not init MTL window");
return NULL;
}
}
// make the context current
MTLSDOps *dstMTLOps = (MTLSDOps *)dstOps->privOps;
mtlc = dstMTLOps->configInfo->context;
if (mtlc == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR,
"MTLContext_SetSurfaces: could not make context current");
return NULL;
}
return mtlc;
}
- (void)resetClip {
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.resetClip");
[_clip reset];
}
- (void)setClipRectX1:(jint)x1 Y1:(jint)y1 X2:(jint)x2 Y2:(jint)y2 {
J2dTraceLn4(J2D_TRACE_INFO, "MTLContext.setClipRect: %d,%d - %d,%d", x1, y1, x2, y2);
[_clip setClipRectX1:x1 Y1:y1 X2:x2 Y2:y2];
}
- (void)beginShapeClip:(BMTLSDOps *)dstOps {
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.beginShapeClip");
[_clip beginShapeClip:dstOps context:self];
// Store the current transform as we need to use identity transform
// for clip spans rendering
[_tempTransform copyFrom:_transform];
[self resetTransform];
}
- (void)endShapeClip:(BMTLSDOps *)dstOps {
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.endShapeClip");
[_clip endShapeClip:dstOps context:self];
// Reset transform for further rendering
[_transform copyFrom:_tempTransform];
}
- (void)resetComposite {
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLContext_ResetComposite");
[_composite reset];
}
- (void)setAlphaCompositeRule:(jint)rule extraAlpha:(jfloat)extraAlpha
flags:(jint)flags {
J2dTraceLn3(J2D_TRACE_INFO, "MTLContext_SetAlphaComposite: rule=%d, extraAlpha=%1.2f, flags=%d", rule, extraAlpha, flags);
[_composite setRule:rule extraAlpha:extraAlpha];
}
- (NSString*)getCompositeDescription {
return [_composite getDescription];
}
- (NSString*)getPaintDescription {
return [_paint getDescription];
}
- (void)setXorComposite:(jint)xp {
J2dTraceLn1(J2D_TRACE_INFO, "MTLContext.setXorComposite: xorPixel=%08x", xp);
[_composite setXORComposite:xp];
}
- (jboolean) useXORComposite {
return ([_composite getCompositeState] == sun_java2d_SunGraphics2D_COMP_XOR);
}
- (void)resetTransform {
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_ResetTransform");
[_transform resetTransform];
}
- (void)setTransformM00:(jdouble) m00 M10:(jdouble) m10
M01:(jdouble) m01 M11:(jdouble) m11
M02:(jdouble) m02 M12:(jdouble) m12 {
J2dTraceLn(J2D_TRACE_INFO, "MTLContext_SetTransform");
[_transform setTransformM00:m00 M10:m10 M01:m01 M11:m11 M02:m02 M12:m12];
}
- (void)resetPaint {
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.resetPaint");
self.paint = [[[MTLPaint alloc] init] autorelease];
}
- (void)setColorPaint:(int)pixel {
J2dTraceLn5(J2D_TRACE_INFO, "MTLContext.setColorPaint: pixel=%08x [r=%d g=%d b=%d a=%d]", pixel, (pixel >> 16) & (0xFF), (pixel >> 8) & 0xFF, (pixel) & 0xFF, (pixel >> 24) & 0xFF);
self.paint = [[[MTLColorPaint alloc] initWithColor:pixel] autorelease];
}
- (void)setGradientPaintUseMask:(jboolean)useMask
cyclic:(jboolean)cyclic
p0:(jdouble)p0
p1:(jdouble)p1
p3:(jdouble)p3
pixel1:(jint)pixel1
pixel2:(jint) pixel2
{
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.setGradientPaintUseMask");
self.paint = [[[MTLGradPaint alloc] initWithUseMask:useMask
cyclic:cyclic
p0:p0
p1:p1
p3:p3
pixel1:pixel1
pixel2:pixel2] autorelease];
}
- (void)setLinearGradientPaint:(jboolean)useMask
linear:(jboolean)linear
cycleMethod:(jint)cycleMethod
// 0 - NO_CYCLE
// 1 - REFLECT
// 2 - REPEAT
numStops:(jint)numStops
p0:(jfloat)p0
p1:(jfloat)p1
p3:(jfloat)p3
fractions:(jfloat*)fractions
pixels:(jint*)pixels
{
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.setLinearGradientPaint");
self.paint = [[[MTLLinearGradPaint alloc] initWithUseMask:useMask
linear:linear
cycleMethod:cycleMethod
numStops:numStops
p0:p0
p1:p1
p3:p3
fractions:fractions
pixels:pixels] autorelease];
}
- (void)setRadialGradientPaint:(jboolean)useMask
linear:(jboolean)linear
cycleMethod:(jboolean)cycleMethod
numStops:(jint)numStops
m00:(jfloat)m00
m01:(jfloat)m01
m02:(jfloat)m02
m10:(jfloat)m10
m11:(jfloat)m11
m12:(jfloat)m12
focusX:(jfloat)focusX
fractions:(void *)fractions
pixels:(void *)pixels
{
J2dTraceLn(J2D_TRACE_INFO, "MTLContext.setRadialGradientPaint");
self.paint = [[[MTLRadialGradPaint alloc] initWithUseMask:useMask
linear:linear
cycleMethod:cycleMethod
numStops:numStops
m00:m00
m01:m01
m02:m02
m10:m10
m11:m11
m12:m12
focusX:focusX
fractions:fractions
pixels:pixels] autorelease];
}
- (void)setTexturePaint:(jboolean)useMask
pSrcOps:(jlong)pSrcOps
filter:(jboolean)filter
xp0:(jdouble)xp0
xp1:(jdouble)xp1
xp3:(jdouble)xp3
yp0:(jdouble)yp0
yp1:(jdouble)yp1
yp3:(jdouble)yp3
{
BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrcOps);
if (srcOps == NULL || srcOps->pTexture == NULL) {
J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_setTexturePaint: texture paint - texture is null");
return;
}
J2dTraceLn1(J2D_TRACE_INFO, "MTLContext.setTexturePaint [tex=%p]", srcOps->pTexture);
self.paint = [[[MTLTexturePaint alloc] initWithUseMask:useMask
textureID:srcOps->pTexture
isOpaque:srcOps->isOpaque
filter:filter
xp0:xp0
xp1:xp1
xp3:xp3
yp0:yp0
yp1:yp1
yp3:yp3] autorelease];
}
- (id<MTLCommandBuffer>)createCommandBuffer {
return [self.commandQueue commandBuffer];
}
/*
* This should be exclusively used only for final blit
* and present of CAMetalDrawable in MTLLayer
*/
- (id<MTLCommandBuffer>)createBlitCommandBuffer {
return [self.blitCommandQueue commandBuffer];
}
-(void)setBufImgOp:(NSObject*)bufImgOp {
if (_bufImgOp != nil) {
[_bufImgOp release]; // context owns bufImgOp object
}
_bufImgOp = bufImgOp;
}
-(NSObject*)getBufImgOp {
return _bufImgOp;
}
@end