1 /* 2 * Copyright (c) 2019, 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 <jlong.h> 29 #include <jni_util.h> 30 #include <math.h> 31 #include <Foundation/NSObjCRuntime.h> 32 33 #include "sun_java2d_metal_MetalRenderer.h" 34 35 #include "MetalRenderer.h" 36 #include "MetalRenderQueue.h" 37 #include "MetalSurfaceData.h" 38 #import "shaders/MetalShaderTypes.h" 39 #include "Trace.h" 40 #include "MetalLayer.h" 41 #import "VertexDataManager.h" 42 43 44 // TODO : Current Color, Gradient etc should have its own class 45 static float drawColor[4] = {0.0, 0.0, 0.0, 0.0}; 46 static int ClipRectangle[4] = {0, 0, 0, 0}; 47 // The current size of our view so we can use this in our render pipeline 48 // static unsigned int viewportSize[2] = {0, 0}; 49 50 void 51 MetalRenderer_DrawLine(MetalContext *mtlc, jint x1, jint y1, jint x2, jint y2) 52 { 53 //J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawLine"); 54 55 //RETURN_IF_NULL(mtlc); 56 57 //CHECK_PREVIOUS_OP(GL_LINES); 58 59 float P1_X, P1_Y; 60 float P2_X, P2_Y; 61 62 if (y1 == y2) { 63 // horizontal 64 float fx1 = (float)x1; 65 float fx2 = (float)x2; 66 float fy = ((float)y1) + 0.2f; 67 68 if (x1 > x2) { 69 float t = fx1; fx1 = fx2; fx2 = t; 70 } 71 72 P1_X = fx1+0.2f; 73 P1_Y = fy; 74 P2_X = fx2+1.2f; 75 P2_Y = fy; 76 } else if (x1 == x2) { 77 // vertical 78 float fx = ((float)x1) + 0.2f; 79 float fy1 = (float)y1; 80 float fy2 = (float)y2; 81 82 if (y1 > y2) { 83 float t = fy1; fy1 = fy2; fy2 = t; 84 } 85 86 P1_X = fx; 87 P1_Y = fy1+0.2f; 88 P2_X = fx; 89 P2_Y = fy2+1.2f; 90 } else { 91 // diagonal 92 float fx1 = (float)x1; 93 float fy1 = (float)y1; 94 float fx2 = (float)x2; 95 float fy2 = (float)y2; 96 97 if (x1 < x2) { 98 fx1 += 0.2f; 99 fx2 += 1.0f; 100 } else { 101 fx1 += 0.8f; 102 fx2 -= 0.2f; 103 } 104 105 if (y1 < y2) { 106 fy1 += 0.2f; 107 fy2 += 1.0f; 108 } else { 109 fy1 += 0.8f; 110 fy2 -= 0.2f; 111 } 112 113 P1_X = fx1; 114 P1_Y = fy1; 115 P2_X = fx2; 116 P2_Y = fy2; 117 } 118 119 // The (x1, y1) & (x2, y2) are in coordinate system : 120 // Top Left (0, 0) : Bottom Right (width and height) 121 // 122 // Metal rendering coordinate system is : 123 // Top Left (-1.0, 1.0) : Bottom Right (1.0, -1.0) 124 // 125 // This coordinate transformation happens in shader code. 126 127 MetalVertex lineVertexData[] = 128 { 129 { {P1_X, P1_Y, 0.0, 1.0}, {drawColor[0], drawColor[1], drawColor[2], drawColor[3]} }, 130 { {P2_X, P2_Y, 0.0, 1.0}, {drawColor[0], drawColor[1], drawColor[2], drawColor[3]} } 131 }; 132 133 //NSLog(@"Drawline ----- x1 : %f, y1 : %f------ x2 : %f, y2 = %f", x1/halfWidth, y1/halfHeight, x2/halfWidth, y2/halfHeight); 134 135 VertexDataManager_addLineVertexData(lineVertexData[0], lineVertexData[1]); 136 } 137 138 139 140 void 141 MetalRenderer_DrawParallelogram(MetalContext *mtlc, 142 jfloat fx11, jfloat fy11, 143 jfloat dx21, jfloat dy21, 144 jfloat dx12, jfloat dy12, 145 jfloat lwr21, jfloat lwr12) 146 { 147 // dx,dy for line width in the "21" and "12" directions. 148 jfloat ldx21 = dx21 * lwr21; 149 jfloat ldy21 = dy21 * lwr21; 150 jfloat ldx12 = dx12 * lwr12; 151 jfloat ldy12 = dy12 * lwr12; 152 153 // calculate origin of the outer parallelogram 154 jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f; 155 jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f; 156 157 /*J2dTraceLn8(J2D_TRACE_INFO, 158 "OGLRenderer_DrawParallelogram " 159 "(x=%6.2f y=%6.2f " 160 "dx1=%6.2f dy1=%6.2f lwr1=%6.2f " 161 "dx2=%6.2f dy2=%6.2f lwr2=%6.2f)", 162 fx11, fy11, 163 dx21, dy21, lwr21, 164 dx12, dy12, lwr12);*/ 165 166 // RETURN_IF_NULL(oglc); 167 168 // CHECK_PREVIOUS_OP(GL_QUADS); 169 170 // Only need to generate 4 quads if the interior still 171 // has a hole in it (i.e. if the line width ratio was 172 // less than 1.0) 173 if (lwr21 < 1.0f && lwr12 < 1.0f) { 174 175 // Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are 176 // relative to whether the dxNN variables are positive 177 // and negative. The math works fine regardless of 178 // their signs, but for conceptual simplicity the 179 // comments will refer to the sides as if the dxNN 180 // were all positive. "TOP" and "BOTTOM" segments 181 // are defined by the dxy21 deltas. "LEFT" and "RIGHT" 182 // segments are defined by the dxy12 deltas. 183 184 // Each segment includes its starting corner and comes 185 // to just short of the following corner. Thus, each 186 // corner is included just once and the only lengths 187 // needed are the original parallelogram delta lengths 188 // and the "line width deltas". The sides will cover 189 // the following relative territories: 190 // 191 // T T T T T R 192 // L R 193 // L R 194 // L R 195 // L R 196 // L B B B B B 197 198 // TOP segment, to left side of RIGHT edge 199 // "width" of original pgram, "height" of hor. line size 200 fx11 = ox11; 201 fy11 = oy11; 202 FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12); 203 204 // RIGHT segment, to top of BOTTOM edge 205 // "width" of vert. line size , "height" of original pgram 206 fx11 = ox11 + dx21; 207 fy11 = oy11 + dy21; 208 FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12); 209 210 // BOTTOM segment, from right side of LEFT edge 211 // "width" of original pgram, "height" of hor. line size 212 fx11 = ox11 + dx12 + ldx21; 213 fy11 = oy11 + dy12 + ldy21; 214 FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12); 215 216 // LEFT segment, from bottom of TOP edge 217 // "width" of vert. line size , "height" of inner pgram 218 fx11 = ox11 + ldx12; 219 fy11 = oy11 + ldy12; 220 FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12); 221 } else { 222 // The line width ratios were large enough to consume 223 // the entire hole in the middle of the parallelogram 224 // so we can just issue one large quad for the outer 225 // parallelogram. 226 dx21 += ldx21; 227 dy21 += ldy21; 228 dx12 += ldx12; 229 dy12 += ldy12; 230 FILL_PGRAM(ox11, oy11, dx21, dy21, dx12, dy12); 231 } 232 } 233 234 235 void 236 MetalRenderer_FillParallelogram(MetalContext *mtlc, 237 jfloat fx11, jfloat fy11, 238 jfloat dx21, jfloat dy21, 239 jfloat dx12, jfloat dy12) 240 { 241 /*J2dTraceLn6(J2D_TRACE_INFO, 242 "OGLRenderer_FillParallelogram " 243 "(x=%6.2f y=%6.2f " 244 "dx1=%6.2f dy1=%6.2f " 245 "dx2=%6.2f dy2=%6.2f)", 246 fx11, fy11, 247 dx21, dy21, 248 dx12, dy12); 249 250 RETURN_IF_NULL(oglc); 251 252 CHECK_PREVIOUS_OP(GL_QUADS);*/ 253 254 FILL_PGRAM(fx11, fy11, dx21, dy21, dx12, dy12); 255 } 256 257 258 void FILL_PGRAM(float fx11, float fy11, float dx21, float dy21, float dx12, float dy12) { 259 260 MetalRenderer_DrawQuad(fx11, fy11, 261 fx11 + dx21, fy11 + dy21, 262 fx11 + dx21 + dx12, fy11 + dy21 + dy12, 263 fx11 + dx12, fy11 + dy12); 264 } 265 266 267 268 void MetalRenderer_DrawQuad(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) { 269 270 // Draw two triangles with given 4 vertices 271 272 // The (x1, y1) & (x2, y2) are in coordinate system : 273 // Top Left (0, 0) : Bottom Right (width and height) 274 // 275 // Metal rendering coordinate system is : 276 // Top Left (-1.0, 1.0) : Bottom Right (1.0, -1.0) 277 // 278 // This coordinate transformation happens in shader code. 279 280 MetalVertex QuadVertexData[] = 281 { 282 { {x1, y1, 0.0, 1.0}, {drawColor[0], drawColor[1], drawColor[2], drawColor[3]} }, 283 { {x2, y2, 0.0, 1.0}, {drawColor[0], drawColor[1], drawColor[2], drawColor[3]} }, 284 { {x3, y3, 0.0, 1.0}, {drawColor[0], drawColor[1], drawColor[2], drawColor[3]} }, 285 { {x4, y4, 0.0, 1.0}, {drawColor[0], drawColor[1], drawColor[2], drawColor[3]} }, 286 }; 287 288 VertexDataManager_addQuadVertexData(QuadVertexData[0], QuadVertexData[1], QuadVertexData[2], QuadVertexData[3]); 289 } 290 291 292 void MetalRenderer_SetColor(MetalContext *mtlc, jint color) { 293 //J2dTraceLn(J2D_TRACE_INFO, "MetalRenderer_SetColor"); 294 unsigned char r = (unsigned char)(color >> 16); 295 unsigned char g = (unsigned char)(color >> 8); 296 unsigned char b = (unsigned char)(color >> 0); 297 unsigned char a = 0xff; 298 299 drawColor[0] = r/255.0; 300 drawColor[1] = g/255.0; 301 drawColor[2] = b/255.0; 302 drawColor[3] = 1.0; 303 304 NSLog(@"MetalRenderer SetColor ----- (%d, %d, %d, %d)", r, g, b, a); 305 } 306 307 308 void MetalRenderer_DrawRect(MetalContext *mtlc, 309 jint x, jint y, jint w, jint h) { 310 //J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawRect"); 311 312 if (w < 0 || h < 0) { 313 return; 314 } 315 316 //RETURN_IF_NULL(oglc); 317 318 if (w < 2 || h < 2) { 319 // If one dimension is less than 2 then there is no 320 // gap in the middle - draw a solid filled rectangle. 321 //CHECK_PREVIOUS_OP(GL_QUADS); 322 //GLRECT_BODY_XYWH(x, y, w+1, h+1); 323 MetalRenderer_FillRect(mtlc, x, y, w+1, h+1); 324 } else { 325 jint fx1 = (jint) (((float)x) + 0.2f); 326 jint fy1 = (jint) (((float)y) + 0.2f); 327 jint fx2 = fx1 + w; 328 jint fy2 = fy1 + h; 329 330 // Avoid drawing the endpoints twice. 331 // Also prefer including the endpoints in the 332 // horizontal sections which draw pixels faster. 333 334 // top 335 MetalRenderer_DrawLine(mtlc, fx1, fy1, fx2+1, fy1); 336 337 // right 338 MetalRenderer_DrawLine(mtlc, fx2, fy1+1, fx2, fy2); 339 340 // bottom 341 MetalRenderer_DrawLine(mtlc, fx1, fy2, fx2+1, fy2); 342 343 344 // left 345 MetalRenderer_DrawLine(mtlc, fx1, fy1+1, fx1, fy2); 346 } 347 } 348 349 350 void 351 MetalRenderer_FillRect(MetalContext *mtlc, jint x, jint y, jint w, jint h) 352 { 353 //J2dTraceLn(J2D_TRACE_INFO, "MetalRenderer_FillRect"); 354 355 if (w <= 0 || h <= 0) { 356 return; 357 } 358 359 //RETURN_IF_NULL(oglc); 360 361 //CHECK_PREVIOUS_OP(GL_QUADS); 362 //GLRECT_BODY_XYWH(x, y, w, h); 363 364 365 MetalRenderer_DrawQuad(x, y, x, y+h, x+w, y+h, x+w, y); 366 367 //NSLog(@"MetalRenderer_FillRect: X, Y(%f, %f) with width, height(%f, %f)", (float)x, (float)y, (float)w, (float)h); 368 } 369 370 // TODO : I think, this should go to metal context 371 void MetalRenderer_SetRectClip(MetalContext *mtlc, jint x1, jint y1, jint x2, jint y2) { 372 373 jint width = x2 - x1; 374 jint height = y2 - y1; 375 376 J2dTraceLn4(J2D_TRACE_INFO, 377 "MetalRenderer_SetRectClip: x=%d y=%d w=%d h=%d", 378 x1, y1, width, height); 379 380 //RETURN_IF_NULL(dstOps); 381 //RETURN_IF_NULL(oglc); 382 //CHECK_PREVIOUS_OP(OGL_STATE_CHANGE); 383 384 if ((width < 0) || (height < 0)) { 385 // use an empty scissor rectangle when the region is empty 386 width = 0; 387 height = 0; 388 } 389 390 //j2d_glDisable(GL_DEPTH_TEST); 391 //j2d_glEnable(GL_SCISSOR_TEST); 392 393 // the scissor rectangle is specified using the lower-left 394 // origin of the clip region (in the framebuffer's coordinate 395 // space), so we must account for the x/y offsets of the 396 // destination surface 397 /*j2d_glScissor(dstOps->xOffset + x1, 398 dstOps->yOffset + dstOps->height - (y1 + height), 399 width, height);*/ 400 401 MetalSDOps *dstOps = MetalRenderQueue_GetCurrentDestination(); 402 403 ClipRectangle[0] = x1;//dstOps->xOffset + x1; 404 ClipRectangle[1] = y1;//dstOps->yOffset + dstOps->height - (y1 + height); 405 ClipRectangle[2] = width; 406 ClipRectangle[3] = height; 407 408 } 409 410 void MetalRenderer_Flush() { 411 412 MetalSDOps* dstOps = MetalRenderQueue_GetCurrentDestination(); 413 MetalLayer* mtlLayer = dstOps->layer; 414 415 unsigned int viewportSize[2] = {mtlLayer.textureWidth, mtlLayer.textureHeight}; 416 417 //Create a render pass descriptor 418 MTLRenderPassDescriptor* mtlRenderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor]; 419 420 //Set the SurfaceData offscreen texture as target texture for the rendering pipeline 421 mtlRenderPassDescriptor.colorAttachments[0].texture = dstOps->mtlTexture; 422 423 mtlRenderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; 424 mtlRenderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.8, 0.8, 0.8, 1.0); 425 mtlRenderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore; 426 427 id<MTLCommandBuffer> mtlCommandBuffer = [dstOps->configInfo->commandQueue commandBuffer]; 428 id<MTLRenderCommandEncoder> renderEncoder = [mtlCommandBuffer renderCommandEncoderWithDescriptor:mtlRenderPassDescriptor]; 429 430 // Configure render enconder with the pipeline state 431 [renderEncoder setRenderPipelineState:mtlLayer.renderPipelineState]; 432 433 // Whatever outside this rectangle won't be drawn 434 // TODO : ClipRectangle should be part of MetalContext or some state maintaining class 435 NSLog(@"Setting Rect Clip : %d, %d, %d, %d", ClipRectangle[0], ClipRectangle[1], ClipRectangle[2], ClipRectangle[3]); 436 MTLScissorRect clip = {ClipRectangle[0], ClipRectangle[1], ClipRectangle[2], ClipRectangle[3]}; 437 [renderEncoder setScissorRect:clip]; 438 439 // --------------------------------------------------------- 440 // DRAW primitives from VertexDataManager 441 // --------------------------------------------------------- 442 [renderEncoder setVertexBuffer:VertexDataManager_getVertexBuffer() offset:0 atIndex:0]; // 0th index 443 444 [renderEncoder setVertexBytes: &viewportSize 445 length: sizeof(viewportSize) 446 atIndex: 1]; // 1st index 447 448 MetalPrimitiveData** allPrimitives = VertexDataManager_getAllPrimitives(); 449 450 int totalPrimitives = VertexDataManager_getNoOfPrimitives(); 451 for (int i = 0; i < totalPrimitives; i++ ) { 452 MetalPrimitiveData* p = allPrimitives[i]; 453 454 NSLog(@"----------------------------------------------"); 455 NSLog(@"Encoding primitive %d", i); 456 NSLog(@"indexCount %d", p->no_of_indices); 457 NSLog(@"indexBufferOffset %d", p->offset_in_index_buffer); 458 NSLog(@"primitiveInstances %d", p->primitiveInstances); 459 NSLog(@"----------------------------------------------"); 460 461 462 [renderEncoder drawIndexedPrimitives: p->type 463 indexCount: (NSUInteger)p->no_of_indices 464 indexType: (MTLIndexType)MTLIndexTypeUInt16 465 indexBuffer: (id<MTLBuffer>)VertexDataManager_getIndexBuffer() 466 indexBufferOffset: (NSUInteger)p->offset_in_index_buffer 467 instanceCount: (NSUInteger)p->primitiveInstances]; 468 } 469 470 //-------------------------------------------------- 471 472 [renderEncoder endEncoding]; 473 474 [mtlCommandBuffer commit]; 475 476 [mtlCommandBuffer waitUntilCompleted]; 477 } 478 479 480 void MetalRenderer_blitToScreenDrawable() { 481 482 MetalSDOps* dstOps = MetalRenderQueue_GetCurrentDestination(); 483 MetalLayer* mtlLayer = dstOps->layer; 484 485 @autoreleasepool { 486 id <CAMetalDrawable> frameDrawable = [mtlLayer nextDrawable]; 487 488 id<MTLCommandBuffer> commandBuffer = [dstOps->configInfo->commandQueue commandBuffer]; 489 490 id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder]; 491 492 //[blitEncoder synchronizeResource:_texture]; 493 494 [blitEncoder copyFromTexture:dstOps->mtlTexture 495 sourceSlice:0 496 sourceLevel:0 497 sourceOrigin:MTLOriginMake(ClipRectangle[0], ClipRectangle[1], 0) 498 sourceSize:MTLSizeMake(dstOps->mtlTexture.width - ClipRectangle[0], dstOps->mtlTexture.height - ClipRectangle[1], 1) 499 toTexture:frameDrawable.texture 500 destinationSlice:0 501 destinationLevel:0 502 destinationOrigin:MTLOriginMake(0, 0, 0)]; 503 504 [blitEncoder endEncoding]; 505 506 [commandBuffer presentDrawable:frameDrawable]; 507 508 [commandBuffer commit]; 509 510 [commandBuffer waitUntilCompleted]; 511 } 512 } 513 514 #endif