1 /*
  2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 #ifndef HEADLESS
 27 
 28 #include <stdlib.h>
 29 
 30 #include "sun_java2d_SunGraphics2D.h"
 31 
 32 #include "jlong.h"
 33 #import "MTLContext.h"
 34 #include "MTLRenderQueue.h"
 35 
 36 
 37 extern jboolean MTLSD_InitMTLWindow(JNIEnv *env, MTLSDOps *mtlsdo);
 38 
 39 static struct TxtVertex verts[PGRAM_VERTEX_COUNT] = {
 40         {{-1.0, 1.0}, {0.0, 0.0}},
 41         {{1.0, 1.0}, {1.0, 0.0}},
 42         {{1.0, -1.0}, {1.0, 1.0}},
 43         {{1.0, -1.0}, {1.0, 1.0}},
 44         {{-1.0, -1.0}, {0.0, 1.0}},
 45         {{-1.0, 1.0}, {0.0, 0.0}}
 46 };
 47 
 48 @implementation MTLCommandBufferWrapper {
 49     id<MTLCommandBuffer> _commandBuffer;
 50     NSMutableArray * _pooledTextures;
 51 }
 52 
 53 - (id) initWithCommandBuffer:(id<MTLCommandBuffer>)cmdBuf {
 54     self = [super init];
 55     if (self) {
 56         _commandBuffer = [cmdBuf retain];
 57         _pooledTextures = [[NSMutableArray alloc] init];
 58     }
 59     return self;
 60 }
 61 
 62 - (id<MTLCommandBuffer>) getCommandBuffer {
 63     return _commandBuffer;
 64 }
 65 
 66 - (void) onComplete { // invoked from completion handler in some pooled thread
 67     for (int c = 0; c < [_pooledTextures count]; ++c)
 68         [[_pooledTextures objectAtIndex:c] releaseTexture];
 69     [_pooledTextures removeAllObjects];
 70 }
 71 
 72 - (void) registerPooledTexture:(MTLPooledTextureHandle *)handle {
 73     [_pooledTextures addObject:handle];
 74 }
 75 
 76 - (void) dealloc {
 77     [self onComplete];
 78 
 79     [self->_pooledTextures release];
 80     [self->_commandBuffer release];
 81     [super dealloc];
 82 }
 83 
 84 @end
 85 
 86 @implementation MTLContext {
 87     MTLCommandBufferWrapper * _commandBufferWrapper;
 88 
 89     MTLComposite *     _composite;
 90     MTLPaint *         _paint;
 91     MTLTransform *     _transform;
 92     MTLClip *           _clip;
 93 
 94     EncoderManager * _encoderManager;
 95 }
 96 
 97 @synthesize textureFunction,
 98             vertexCacheEnabled, aaEnabled, device, library, pipelineStateStorage,
 99             commandQueue, vertexBuffer,
100             texturePool;
101 
102 - (id)initWithDevice:(id<MTLDevice>)d shadersLib:(NSString*)shadersLib {
103     self = [super init];
104     if (self) {
105         // Initialization code here.
106         device = d;
107 
108         texturePool = [[MTLTexturePool alloc] initWithDevice:device];
109         pipelineStateStorage = [[MTLPipelineStatesStorage alloc] initWithDevice:device shaderLibPath:shadersLib];
110 
111         vertexBuffer = [device newBufferWithBytes:verts
112                                            length:sizeof(verts)
113                                           options:MTLResourceCPUCacheModeDefaultCache];
114 
115         NSError *error = nil;
116 
117         library = [device newLibraryWithFile:shadersLib error:&error];
118         if (!library) {
119             NSLog(@"Failed to load library. error %@", error);
120             exit(0);
121         }
122 
123         _encoderManager = [[EncoderManager alloc] init];
124         [_encoderManager setContext:self];
125         _composite = [[MTLComposite alloc] init];
126         _paint = [[MTLPaint alloc] init];
127         _transform = [[MTLTransform alloc] init];
128         _clip = [[MTLClip alloc] init];
129 
130         _commandBufferWrapper = nil;
131 
132         // Create command queue
133         commandQueue = [device newCommandQueue];
134     }
135     return self;
136 }
137 
138 - (void)dealloc {
139     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.dealloc");
140 
141     self.texturePool = nil;
142     self.library = nil;
143     self.vertexBuffer = nil;
144     self.commandQueue = nil;
145     self.pipelineStateStorage = nil;
146     [_encoderManager release];
147     [_composite release];
148     [_paint release];
149     [_transform release];
150     [_clip release];
151     [super dealloc];
152 }
153 
154  - (MTLCommandBufferWrapper *) getCommandBufferWrapper {
155     if (_commandBufferWrapper == nil) {
156         J2dTraceLn(J2D_TRACE_VERBOSE, "MTLContext : commandBuffer is NULL");
157         // NOTE: Command queues are thread-safe and allow multiple outstanding command buffers to be encoded simultaneously.
158         _commandBufferWrapper = [[MTLCommandBufferWrapper alloc] initWithCommandBuffer:[self.commandQueue commandBuffer]];// released in [layer blitTexture]
159     }
160     return _commandBufferWrapper;
161 }
162 
163 - (MTLCommandBufferWrapper *) pullCommandBufferWrapper {
164     MTLCommandBufferWrapper * result = _commandBufferWrapper;
165     _commandBufferWrapper = nil;
166     return result;
167 }
168 
169 + (MTLContext*) setSurfacesEnv:(JNIEnv*)env src:(jlong)pSrc dst:(jlong)pDst {
170     BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrc);
171     BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDst);
172     MTLContext *mtlc = NULL;
173 
174     if (srcOps == NULL || dstOps == NULL) {
175         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_SetSurfaces: ops are null");
176         return NULL;
177     }
178 
179     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);
180 
181     if (dstOps->drawableType == MTLSD_TEXTURE) {
182         J2dRlsTraceLn(J2D_TRACE_ERROR,
183                       "MTLContext_SetSurfaces: texture cannot be used as destination");
184         return NULL;
185     }
186 
187     if (dstOps->drawableType == MTLSD_UNDEFINED) {
188         // initialize the surface as an OGLSD_WINDOW
189         if (!MTLSD_InitMTLWindow(env, dstOps)) {
190             J2dRlsTraceLn(J2D_TRACE_ERROR,
191                           "MTLContext_SetSurfaces: could not init OGL window");
192             return NULL;
193         }
194     }
195 
196     // make the context current
197     MTLSDOps *dstCGLOps = (MTLSDOps *)dstOps->privOps;
198     mtlc = dstCGLOps->configInfo->context;
199 
200     if (mtlc == NULL) {
201         J2dRlsTraceLn(J2D_TRACE_ERROR,
202                       "MTLContext_SetSurfaces: could not make context current");
203         return NULL;
204     }
205 
206     // perform additional one-time initialization, if necessary
207     if (dstOps->needsInit) {
208         if (dstOps->isOpaque) {
209             // in this case we are treating the destination as opaque, but
210             // to do so, first we need to ensure that the alpha channel
211             // is filled with fully opaque values (see 6319663)
212             //MTLContext_InitAlphaChannel();
213         }
214         dstOps->needsInit = JNI_FALSE;
215     }
216 
217     return mtlc;
218 }
219 
220 - (void)resetClip {
221     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.resetClip");
222     [_clip reset];
223 }
224 
225 - (void)setClipRectX1:(jint)x1 Y1:(jint)y1 X2:(jint)x2 Y2:(jint)y2 {
226     [_clip setClipRectX1:x1 Y1:y1 X2:x2 Y2:y2];
227 }
228 
229 - (void)beginShapeClip:(BMTLSDOps *)dstOps {
230     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.beginShapeClip");
231     [_clip beginShapeClip:dstOps context:self];
232 }
233 
234 - (void)endShapeClip:(BMTLSDOps *)dstOps {
235     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.endShapeClip");
236     [_clip endShapeClip:dstOps context:self];
237 }
238 
239 - (void)resetComposite {
240     J2dTraceLn(J2D_TRACE_VERBOSE, "MTLContext_ResetComposite");
241     [_composite reset];
242 }
243 
244 - (void)setAlphaCompositeRule:(jint)rule extraAlpha:(jfloat)extraAlpha
245                         flags:(jint)flags {
246     J2dTraceLn3(J2D_TRACE_INFO, "MTLContext_SetAlphaComposite: rule=%d, extraAlpha=%1.2f, flags=%d", rule, extraAlpha, flags);
247 
248     [_composite setRule:rule extraAlpha:extraAlpha];
249 }
250 
251 - (NSString*)getCompositeDescription {
252     return [_composite getDescription];
253 }
254 
255 - (NSString*)getPaintDescription {
256     return [_paint getDescription];
257 }
258 
259 - (void)setXorComposite:(jint)xp {
260     J2dTraceLn1(J2D_TRACE_INFO, "MTLContext.setXorComposite: xorPixel=%08x", xp);
261 
262     [_composite setXORComposite:xp];
263 }
264 
265 - (jboolean)isBlendingDisabled:(jboolean) isSrcOpaque {
266     return [_composite isBlendingDisabled:isSrcOpaque];
267 }
268 
269 
270 - (void)resetTransform {
271     J2dTraceLn(J2D_TRACE_INFO, "MTLContext_ResetTransform");
272     [_transform resetTransform];
273 }
274 
275 - (void)setTransformM00:(jdouble) m00 M10:(jdouble) m10
276                     M01:(jdouble) m01 M11:(jdouble) m11
277                     M02:(jdouble) m02 M12:(jdouble) m12 {
278     J2dTraceLn(J2D_TRACE_INFO, "MTLContext_SetTransform");
279     [_transform setTransformM00:m00 M10:m10 M01:m01 M11:m11 M02:m02 M12:m12];
280 }
281 
282 - (jboolean)initBlitTileTexture {
283     //TODO
284     J2dTraceLn(J2D_TRACE_INFO, "MTLContext_InitBlitTileTexture -- :TODO");
285 
286     return JNI_TRUE;
287 }
288 
289 - (jint)createBlitTextureFormat:(jint)internalFormat pixelFormat:(jint)pixelFormat
290                           width:(jint)width height:(jint)height {
291     J2dTraceLn(J2D_TRACE_INFO, "MTLContext_InitBlitTileTexture -- :TODO");
292 
293     //TODO
294     return 0;
295 }
296 
297 - (void)resetPaint {
298     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.resetPaint");
299     [_paint reset];
300 }
301 
302 - (void)setColorPaint:(int)pixel {
303     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);
304     [_paint setColor:pixel];
305 }
306 
307 - (void)setGradientPaintUseMask:(jboolean)useMask
308                          cyclic:(jboolean)cyclic
309                              p0:(jdouble)p0
310                              p1:(jdouble)p1
311                              p3:(jdouble)p3
312                          pixel1:(jint)pixel1
313                          pixel2:(jint) pixel2
314 {
315     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.setGradientPaintUseMask");
316     [_paint setGradientUseMask:useMask
317                             cyclic:cyclic
318                                 p0:p0
319                                 p1:p1
320                                 p3:p3
321                             pixel1:pixel1
322                             pixel2:pixel2];
323 }
324 
325 - (void)setLinearGradientPaint:(jboolean)useMask
326                         linear:(jboolean)linear
327                    cycleMethod:(jboolean)cycleMethod
328                       numStops:(jint)numStops
329                             p0:(jfloat)p0
330                             p1:(jfloat)p1
331                             p3:(jfloat)p3
332                      fractions:(void *)fractions
333                         pixels:(void *)pixels
334 {
335     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.setLinearGradientPaint");
336     [_paint setLinearGradient:useMask
337                        linear:linear
338                   cycleMethod:cycleMethod
339                      numStops:numStops
340                            p0:p0
341                            p1:p1
342                            p3:p3
343                     fractions:fractions
344                        pixels:pixels];
345 }
346 
347 - (void)setRadialGradientPaint:(jboolean)useMask
348                         linear:(jboolean)linear
349                    cycleMethod:(jboolean)cycleMethod
350                       numStops:(jint)numStops
351                            m00:(jfloat)m00
352                            m01:(jfloat)m01
353                            m02:(jfloat)m02
354                            m10:(jfloat)m10
355                            m11:(jfloat)m11
356                            m12:(jfloat)m12
357                         focusX:(jfloat)focusX
358                      fractions:(void *)fractions
359                         pixels:(void *)pixels
360 {
361     J2dTraceLn(J2D_TRACE_INFO, "MTLContext.setRadialGradientPaint");
362     [_paint setRadialGradient:useMask
363                        linear:linear
364                   cycleMethod:cycleMethod
365                      numStops:numStops
366                           m00:m00
367                           m01:m01
368                           m02:m02
369                           m10:m10
370                           m11:m11
371                           m12:m12
372                        focusX:focusX
373                     fractions:fractions
374                        pixels:pixels];
375 }
376 
377 - (void)setTexturePaint:(jboolean)useMask
378                 pSrcOps:(jlong)pSrcOps
379                  filter:(jboolean)filter
380                     xp0:(jdouble)xp0
381                     xp1:(jdouble)xp1
382                     xp3:(jdouble)xp3
383                     yp0:(jdouble)yp0
384                     yp1:(jdouble)yp1
385                     yp3:(jdouble)yp3
386 {
387     BMTLSDOps *srcOps = (BMTLSDOps *)jlong_to_ptr(pSrcOps);
388     
389     if (srcOps == NULL || srcOps->pTexture == NULL) {
390         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLContext_setTexturePaint: texture paint - texture is null");
391         return;
392     }
393 
394     J2dTraceLn1(J2D_TRACE_INFO, "MTLContext.setTexturePaint [tex=%p]", srcOps->pTexture);
395 
396 
397     [_paint setTexture:useMask
398                textureID:srcOps->pTexture
399                 filter:filter
400                    xp0:xp0
401                    xp1:xp1
402                    xp3:xp3
403                    yp0:yp0
404                    yp1:yp1
405                    yp3:yp3];
406 }
407 
408 - (id<MTLCommandBuffer>)createBlitCommandBuffer {
409     return [self.commandQueue commandBuffer];
410 }
411 
412 @end
413 
414 /*
415  * Class:     sun_java2d_metal_MTLContext
416  * Method:    getMTLIdString
417  * Signature: ()Ljava/lang/String;
418  */
419 JNIEXPORT jstring JNICALL Java_sun_java2d_metal_MTLContext_getMTLIdString
420   (JNIEnv *env, jclass mtlcc)
421 {
422     char *vendor, *renderer, *version;
423     char *pAdapterId;
424     jobject ret = NULL;
425     int len;
426 
427     return NULL;
428 }
429 
430 #endif /* !HEADLESS */