src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MetalRenderer.m
branchmetal-prototype-branch
changeset 57416 e153174dba06
parent 57400 978ffc56771f
child 57417 28582d575a98
equal deleted inserted replaced
57400:978ffc56771f 57416:e153174dba06
     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