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 <jlong.h>
  29 #include <jni_util.h>
  30 #include <math.h>
  31 
  32 #include "sun_java2d_metal_MTLRenderer.h"
  33 
  34 #include "MTLRenderer.h"
  35 #include "MTLRenderQueue.h"
  36 #include "MTLSurfaceData.h"
  37 #include "MTLUtils.h"
  38 #import "MTLLayer.h"
  39 
  40 void MTLRenderer_FillParallelogramMetal(
  41     MTLContext* mtlc, id<MTLTexture> dest, jfloat x, jfloat y, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2)
  42 {
  43     if (mtlc == NULL || dest == nil)
  44         return;
  45 
  46     J2dTraceLn7(J2D_TRACE_INFO,
  47                 "MTLRenderer_FillParallelogramMetal "
  48                 "(x=%6.2f y=%6.2f "
  49                 "dx1=%6.2f dy1=%6.2f "
  50                 "dx2=%6.2f dy2=%6.2f dst tex=%p)",
  51                 x, y,
  52                 dx1, dy1,
  53                 dx2, dy2, dest);
  54 
  55     struct Vertex verts[PGRAM_VERTEX_COUNT] = {
  56     { {(2.0*x/dest.width) - 1.0,
  57        2.0*(1.0 - y/dest.height) - 1.0, 0.0}},
  58 
  59     { {2.0*(x+dx1)/dest.width - 1.0,
  60       2.0*(1.0 - (y+dy1)/dest.height) - 1.0, 0.0}},
  61 
  62     { {2.0*(x+dx2)/dest.width - 1.0,
  63       2.0*(1.0 - (y+dy2)/dest.height) - 1.0, 0.0}},
  64 
  65     { {2.0*(x+dx1)/dest.width - 1.0,
  66       2.0*(1.0 - (y+dy1)/dest.height) - 1.0, 0.0}},
  67 
  68     { {2.0*(x + dx1 + dx2)/dest.width - 1.0,
  69       2.0*(1.0 - (y+ dy1 + dy2)/dest.height) - 1.0, 0.0}},
  70 
  71     { {2.0*(x+dx2)/dest.width - 1.0,
  72       2.0*(1.0 - (y+dy2)/dest.height) - 1.0, 0.0},
  73     }};
  74 
  75     // Encode render command.
  76     id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dest];
  77     if (mtlEncoder == nil)
  78         return;
  79 
  80     [mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
  81     [mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount: PGRAM_VERTEX_COUNT];
  82     [mtlEncoder endEncoding];
  83 }
  84 
  85 /**
  86  * Note: Some of the methods in this file apply a "magic number"
  87  * translation to line segments.  The OpenGL specification lays out the
  88  * "diamond exit rule" for line rasterization, but it is loose enough to
  89  * allow for a wide range of line rendering hardware.  (It appears that
  90  * some hardware, such as the Nvidia GeForce2 series, does not even meet
  91  * the spec in all cases.)  As such it is difficult to find a mapping
  92  * between the Java2D and OpenGL line specs that works consistently across
  93  * all hardware combinations.
  94  *
  95  * Therefore the "magic numbers" you see here have been empirically derived
  96  * after testing on a variety of graphics hardware in order to find some
  97  * reasonable middle ground between the two specifications.  The general
  98  * approach is to apply a fractional translation to vertices so that they
  99  * hit pixel centers and therefore touch the same pixels as in our other
 100  * pipelines.  Emphasis was placed on finding values so that MTL lines with
 101  * a slope of +/- 1 hit all the same pixels as our other (software) loops.
 102  * The stepping in other diagonal lines rendered with MTL may deviate
 103  * slightly from those rendered with our software loops, but the most
 104  * important thing is that these magic numbers ensure that all MTL lines
 105  * hit the same endpoints as our software loops.
 106  *
 107  * If you find it necessary to change any of these magic numbers in the
 108  * future, just be sure that you test the changes across a variety of
 109  * hardware to ensure consistent rendering everywhere.
 110  */
 111 
 112 void MTLRenderer_DrawLine(MTLContext *mtlc, BMTLSDOps * dstOps, jint x1, jint y1, jint x2, jint y2) {
 113     if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
 114         J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawLine: dest is null");
 115         return;
 116     }
 117 
 118     J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawLine (x1=%1.2f y1=%1.2f x2=%1.2f y2=%1.2f), dst tex=%p", x1, y1, x2, y2, dstOps->pTexture);
 119 
 120     id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dstOps->pTexture];
 121     if (mtlEncoder == nil)
 122         return;
 123 
 124     struct Vertex verts[2] = {
 125             {{x1, y1, 0.0}},
 126             {{x2, y2, 0.0}}
 127     };
 128 
 129     [mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
 130     [mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2];
 131     [mtlEncoder endEncoding];
 132 }
 133 
 134 void MTLRenderer_DrawRect(MTLContext *mtlc, BMTLSDOps * dstOps, jint x, jint y, jint w, jint h) {
 135     if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
 136         J2dTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawRect: dest is null");
 137         return;
 138     }
 139 
 140     id<MTLTexture> dest = dstOps->pTexture;
 141     J2dTraceLn5(J2D_TRACE_INFO, "MTLRenderer_DrawRect (x=%d y=%d w=%d h=%d), dst tex=%p", x, y, w, h, dest);
 142 
 143     // TODO: use DrawParallelogram(x, y, w, h, lw=1, lh=1)
 144     id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dest];
 145     if (mtlEncoder == nil)
 146         return;
 147 
 148     const int verticesCount = 5;
 149     struct Vertex vertices[verticesCount] = {
 150             {{x, y, 0.0}},
 151             {{x + w, y, 0.0}},
 152             {{x + w, y + h, 0.0}},
 153             {{x, y + h, 0.0}},
 154             {{x, y, 0.0}},
 155     };
 156     [mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer];
 157     [mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:verticesCount];
 158     [mtlEncoder endEncoding];
 159 }
 160 
 161 const int POLYLINE_BUF_SIZE = 64;
 162 
 163 static void fillVertex(struct Vertex * vertex, int x, int y) {
 164     vertex->position[0] = x;
 165     vertex->position[1] = y;
 166     vertex->position[2] = 0;
 167 }
 168 
 169 void MTLRenderer_DrawPoly(MTLContext *mtlc, BMTLSDOps * dstOps,
 170                      jint nPoints, jint isClosed,
 171                      jint transX, jint transY,
 172                      jint *xPoints, jint *yPoints)
 173 {
 174     // Note that BufferedRenderPipe.drawPoly() has already rejected polys
 175     // with nPoints<2, so we can be certain here that we have nPoints>=2.
 176     if (xPoints == NULL || yPoints == NULL || nPoints < 2) { // just for insurance
 177         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: points array is empty");
 178         return;
 179     }
 180 
 181     if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
 182         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_DrawPoly: dest is null");
 183         return;
 184     }
 185 
 186     J2dTraceLn4(J2D_TRACE_INFO, "MTLRenderer_DrawPoly: %d points, transX=%d, transY=%d, dst tex=%p", nPoints, transX, transY, dstOps->pTexture);
 187 
 188     __block struct {
 189         struct Vertex verts[POLYLINE_BUF_SIZE];
 190     } pointsChunk;
 191 
 192     jint prevX = *(xPoints++);
 193     jint prevY = *(yPoints++);
 194     --nPoints;
 195     const jint firstX = prevX;
 196     const jint firstY = prevY;
 197     while (nPoints > 0) {
 198         fillVertex(pointsChunk.verts, prevX + transX, prevY + transY);
 199 
 200         const bool isLastChunk = nPoints + 1 <= POLYLINE_BUF_SIZE;
 201         __block int chunkSize = isLastChunk ? nPoints : POLYLINE_BUF_SIZE - 1;
 202 
 203         for (int i = 1; i < chunkSize; i++) {
 204             prevX = *(xPoints++);
 205             prevY = *(yPoints++);
 206             fillVertex(pointsChunk.verts + i, prevX + transX, prevY + transY);
 207         }
 208 
 209         bool drawCloseSegment = false;
 210         if (isClosed && isLastChunk) {
 211             if (chunkSize + 2 <= POLYLINE_BUF_SIZE) {
 212                 fillVertex(pointsChunk.verts + chunkSize, firstX + transX, firstY + transY);
 213                 ++chunkSize;
 214             } else
 215                 drawCloseSegment = true;
 216         }
 217 
 218         nPoints -= chunkSize;
 219         id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dstOps->pTexture];
 220         if (mtlEncoder == nil)
 221             return;
 222 
 223         [mtlEncoder setVertexBytes:pointsChunk.verts length:sizeof(pointsChunk.verts) atIndex:MeshVertexBuffer];
 224         [mtlEncoder drawPrimitives:MTLPrimitiveTypeLineStrip vertexStart:0 vertexCount:chunkSize + 1];
 225         if (drawCloseSegment) {
 226             struct Vertex vertices[2] = {
 227                     {{prevX + transX, prevY + transY, 0.0}},
 228                     {{firstX + transX, firstY + transY, 0.0}},
 229             };
 230             [mtlEncoder setVertexBytes:vertices length:sizeof(vertices) atIndex:MeshVertexBuffer];
 231             [mtlEncoder drawPrimitives:MTLPrimitiveTypeLine vertexStart:0 vertexCount:2];
 232         }
 233 
 234         [mtlEncoder endEncoding];
 235     }
 236 }
 237 
 238 JNIEXPORT void JNICALL
 239 Java_sun_java2d_metal_MTLRenderer_drawPoly
 240     (JNIEnv *env, jobject mtlr,
 241      jintArray xpointsArray, jintArray ypointsArray,
 242      jint nPoints, jboolean isClosed,
 243      jint transX, jint transY)
 244 {
 245     jint *xPoints, *yPoints;
 246     //TODO
 247     J2dTraceNotImplPrimitive("MTLRenderer_drawPoly");
 248     J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_drawPoly");
 249 }
 250 
 251 void
 252 MTLRenderer_DrawScanlines(MTLContext *mtlc, BMTLSDOps * dstOps,
 253                           jint scanlineCount, jint *scanlines)
 254 {
 255     //TODO
 256     J2dTraceNotImplPrimitive("MTLRenderer_DrawScanlines");
 257     J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_DrawScanlines");
 258 }
 259 
 260 void
 261 MTLRenderer_FillRect(MTLContext *mtlc, BMTLSDOps * dstOps, jint x, jint y, jint w, jint h)
 262 {
 263     //TODO
 264     J2dTraceNotImplPrimitive("MTLRenderer_FillRect");
 265     J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillRect");
 266 }
 267 
 268 const int SPAN_BUF_SIZE=64;
 269 
 270 void
 271 MTLRenderer_FillSpans(MTLContext *mtlc, BMTLSDOps * dstOps, jint spanCount, jint *spans)
 272 {
 273     J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_FillSpans");
 274     if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
 275         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillSpans: dest is null");
 276         return;
 277     }
 278 
 279     while (spanCount > 0) {
 280         __block struct {
 281             jfloat spns[SPAN_BUF_SIZE*4];
 282         } spanStruct;
 283 
 284         __block jfloat sc = spanCount > SPAN_BUF_SIZE ? SPAN_BUF_SIZE : spanCount;
 285 
 286         for (int i = 0; i < sc; i++) {
 287             spanStruct.spns[i * 4] = *(spans++);
 288             spanStruct.spns[i * 4 + 1] = *(spans++);
 289             spanStruct.spns[i * 4 + 2] = *(spans++);
 290             spanStruct.spns[i * 4 + 3] = *(spans++);
 291         }
 292 
 293         spanCount -= sc;
 294 
 295         id<MTLTexture> dest = dstOps->pTexture;
 296         id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dest];
 297         if (mtlEncoder == nil)
 298             return;
 299 
 300         for (int i = 0; i < sc; i++) {
 301             jfloat x1 = spanStruct.spns[i * 4];
 302             jfloat y1 = spanStruct.spns[i * 4 + 1];
 303             jfloat x2 = spanStruct.spns[i * 4 + 2];
 304             jfloat y2 = spanStruct.spns[i * 4 + 3];
 305 
 306             struct Vertex verts[PGRAM_VERTEX_COUNT] = {
 307                 {{x1, y1, 0.0}},
 308                 {{x2, y1, 0.0}},
 309                 {{x1, y2, 0.0}},
 310                 {{x2, y1, 0.0}},
 311                 {{x2, y2, 0.0}},
 312                 {{x1, y2, 0.0},
 313             }};
 314 
 315             [mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
 316             [mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:PGRAM_VERTEX_COUNT];
 317         }
 318 
 319         [mtlEncoder endEncoding];
 320         [mtlEncoder release];
 321     }
 322 }
 323 
 324 void
 325 MTLRenderer_FillParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
 326                               jfloat fx11, jfloat fy11,
 327                               jfloat dx21, jfloat dy21,
 328                               jfloat dx12, jfloat dy12)
 329 {
 330     J2dTracePrimitive("MTLRenderer_FillParallelogram");
 331 
 332     if (mtlc == NULL || dstOps == NULL || dstOps->pTexture == NULL) {
 333         J2dRlsTraceLn(J2D_TRACE_ERROR, "MTLRenderer_FillParallelogram: current dest is null");
 334         return;
 335     }
 336 
 337     id<MTLTexture> dest = dstOps->pTexture;
 338     J2dTraceLn7(J2D_TRACE_INFO,
 339                 "MTLRenderer_FillParallelogram "
 340                 "(x=%6.2f y=%6.2f "
 341                 "dx1=%6.2f dy1=%6.2f "
 342                 "dx2=%6.2f dy2=%6.2f dst tex=%p)",
 343                 fx11, fy11,
 344                 dx21, dy21,
 345                 dx12, dy12, dest);
 346 
 347     struct Vertex verts[PGRAM_VERTEX_COUNT] = {
 348             { {fx11, fy11, 0.0}},
 349             { {fx11+dx21, fy11+dy21, 0.0}},
 350             { {fx11+dx12, fy11+dy12, 0.0}},
 351             { {fx11+dx21, fy11+dy21, 0.0}},
 352             { {fx11 + dx21 + dx12, fy11+ dy21 + dy12, 0.0}},
 353             { {fx11+dx12, fy11+dy12, 0.0},
 354             }};
 355 
 356     // Encode render command.
 357     id<MTLRenderCommandEncoder> mtlEncoder = [mtlc createRenderEncoderForDest:dest];
 358     if (mtlEncoder == nil)
 359         return;
 360 
 361     [mtlEncoder setVertexBytes:verts length:sizeof(verts) atIndex:MeshVertexBuffer];
 362     [mtlEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount: PGRAM_VERTEX_COUNT];
 363     [mtlEncoder endEncoding];
 364 }
 365 
 366 void
 367 MTLRenderer_DrawParallelogram(MTLContext *mtlc, BMTLSDOps * dstOps,
 368                               jfloat fx11, jfloat fy11,
 369                               jfloat dx21, jfloat dy21,
 370                               jfloat dx12, jfloat dy12,
 371                               jfloat lwr21, jfloat lwr12)
 372 {
 373     //TODO
 374     J2dTraceNotImplPrimitive("MTLRenderer_DrawParallelogram");
 375     // dx,dy for line width in the "21" and "12" directions.
 376     jfloat ldx21 = dx21 * lwr21;
 377     jfloat ldy21 = dy21 * lwr21;
 378     jfloat ldx12 = dx12 * lwr12;
 379     jfloat ldy12 = dy12 * lwr12;
 380 
 381     // calculate origin of the outer parallelogram
 382     jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f;
 383     jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f;
 384 
 385     J2dTraceLn8(J2D_TRACE_INFO,
 386                 "MTLRenderer_DrawParallelogram "
 387                 "(x=%6.2f y=%6.2f "
 388                 "dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
 389                 "dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
 390                 fx11, fy11,
 391                 dx21, dy21, lwr21,
 392                 dx12, dy12, lwr12);
 393 
 394 }
 395 
 396 static GLhandleARB aaPgramProgram = 0;
 397 
 398 /*
 399  * This shader fills the space between an outer and inner parallelogram.
 400  * It can be used to draw an outline by specifying both inner and outer
 401  * values.  It fills pixels by estimating what portion falls inside the
 402  * outer shape, and subtracting an estimate of what portion falls inside
 403  * the inner shape.  Specifying both inner and outer values produces a
 404  * standard "wide outline".  Specifying an inner shape that falls far
 405  * outside the outer shape allows the same shader to fill the outer
 406  * shape entirely since pixels that fall within the outer shape are never
 407  * inside the inner shape and so they are filled based solely on their
 408  * coverage of the outer shape.
 409  *
 410  * The setup code renders this shader over the bounds of the outer
 411  * shape (or the only shape in the case of a fill operation) and
 412  * sets the texture 0 coordinates so that 0,0=>0,1=>1,1=>1,0 in those
 413  * texture coordinates map to the four corners of the parallelogram.
 414  * Similarly the texture 1 coordinates map the inner shape to the
 415  * unit square as well, but in a different coordinate system.
 416  *
 417  * When viewed in the texture coordinate systems the parallelograms
 418  * we are filling are unit squares, but the pixels have then become
 419  * tiny parallelograms themselves.  Both of the texture coordinate
 420  * systems are affine transforms so the rate of change in X and Y
 421  * of the texture coordinates are essentially constants and happen
 422  * to correspond to the size and direction of the slanted sides of
 423  * the distorted pixels relative to the "square mapped" boundary
 424  * of the parallelograms.
 425  *
 426  * The shader uses the dFdx() and dFdy() functions to measure the "rate
 427  * of change" of these texture coordinates and thus gets an accurate
 428  * measure of the size and shape of a pixel relative to the two
 429  * parallelograms.  It then uses the bounds of the size and shape
 430  * of a pixel to intersect with the unit square to estimate the
 431  * coverage of the pixel.  Unfortunately, without a lot more work
 432  * to calculate the exact area of intersection between a unit
 433  * square (the original parallelogram) and a parallelogram (the
 434  * distorted pixel), this shader only approximates the pixel
 435  * coverage, but emperically the estimate is very useful and
 436  * produces visually pleasing results, if not theoretically accurate.
 437  */
 438 static const char *aaPgramShaderSource =
 439     "void main() {"
 440     // Calculate the vectors for the "legs" of the pixel parallelogram
 441     // for the outer parallelogram.
 442     "    vec2 oleg1 = dFdx(gl_TexCoord[0].st);"
 443     "    vec2 oleg2 = dFdy(gl_TexCoord[0].st);"
 444     // Calculate the bounds of the distorted pixel parallelogram.
 445     "    vec2 corner = gl_TexCoord[0].st - (oleg1+oleg2)/2.0;"
 446     "    vec2 omin = min(corner, corner+oleg1);"
 447     "    omin = min(omin, corner+oleg2);"
 448     "    omin = min(omin, corner+oleg1+oleg2);"
 449     "    vec2 omax = max(corner, corner+oleg1);"
 450     "    omax = max(omax, corner+oleg2);"
 451     "    omax = max(omax, corner+oleg1+oleg2);"
 452     // Calculate the vectors for the "legs" of the pixel parallelogram
 453     // for the inner parallelogram.
 454     "    vec2 ileg1 = dFdx(gl_TexCoord[1].st);"
 455     "    vec2 ileg2 = dFdy(gl_TexCoord[1].st);"
 456     // Calculate the bounds of the distorted pixel parallelogram.
 457     "    corner = gl_TexCoord[1].st - (ileg1+ileg2)/2.0;"
 458     "    vec2 imin = min(corner, corner+ileg1);"
 459     "    imin = min(imin, corner+ileg2);"
 460     "    imin = min(imin, corner+ileg1+ileg2);"
 461     "    vec2 imax = max(corner, corner+ileg1);"
 462     "    imax = max(imax, corner+ileg2);"
 463     "    imax = max(imax, corner+ileg1+ileg2);"
 464     // Clamp the bounds of the parallelograms to the unit square to
 465     // estimate the intersection of the pixel parallelogram with
 466     // the unit square.  The ratio of the 2 rectangle areas is a
 467     // reasonable estimate of the proportion of coverage.
 468     "    vec2 o1 = clamp(omin, 0.0, 1.0);"
 469     "    vec2 o2 = clamp(omax, 0.0, 1.0);"
 470     "    float oint = (o2.y-o1.y)*(o2.x-o1.x);"
 471     "    float oarea = (omax.y-omin.y)*(omax.x-omin.x);"
 472     "    vec2 i1 = clamp(imin, 0.0, 1.0);"
 473     "    vec2 i2 = clamp(imax, 0.0, 1.0);"
 474     "    float iint = (i2.y-i1.y)*(i2.x-i1.x);"
 475     "    float iarea = (imax.y-imin.y)*(imax.x-imin.x);"
 476     // Proportion of pixel in outer shape minus the proportion
 477     // of pixel in the inner shape == the coverage of the pixel
 478     // in the area between the two.
 479     "    float coverage = oint/oarea - iint / iarea;"
 480     "    gl_FragColor = gl_Color * coverage;"
 481     "}";
 482 
 483 #define ADJUST_PGRAM(V1, DV, V2) \
 484     do { \
 485         if ((DV) >= 0) { \
 486             (V2) += (DV); \
 487         } else { \
 488             (V1) += (DV); \
 489         } \
 490     } while (0)
 491 
 492 // Invert the following transform:
 493 // DeltaT(0, 0) == (0,       0)
 494 // DeltaT(1, 0) == (DX1,     DY1)
 495 // DeltaT(0, 1) == (DX2,     DY2)
 496 // DeltaT(1, 1) == (DX1+DX2, DY1+DY2)
 497 // TM00 = DX1,   TM01 = DX2,   (TM02 = X11)
 498 // TM10 = DY1,   TM11 = DY2,   (TM12 = Y11)
 499 // Determinant = TM00*TM11 - TM01*TM10
 500 //             =  DX1*DY2  -  DX2*DY1
 501 // Inverse is:
 502 // IM00 =  TM11/det,   IM01 = -TM01/det
 503 // IM10 = -TM10/det,   IM11 =  TM00/det
 504 // IM02 = (TM01 * TM12 - TM11 * TM02) / det,
 505 // IM12 = (TM10 * TM02 - TM00 * TM12) / det,
 506 
 507 #define DECLARE_MATRIX(MAT) \
 508     jfloat MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12
 509 
 510 #define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \
 511     do { \
 512         jfloat det = DX1*DY2 - DX2*DY1; \
 513         if (det == 0) { \
 514             RET_CODE; \
 515         } \
 516         MAT ## 00 = DY2/det; \
 517         MAT ## 01 = -DX2/det; \
 518         MAT ## 10 = -DY1/det; \
 519         MAT ## 11 = DX1/det; \
 520         MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \
 521         MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \
 522     } while (0)
 523 
 524 #define TRANSFORM(MAT, TX, TY, X, Y) \
 525     do { \
 526         TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \
 527         TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \
 528     } while (0)
 529 
 530 void
 531 MTLRenderer_FillAAParallelogram(MTLContext *mtlc, BMTLSDOps *dstOps,
 532                                 jfloat fx11, jfloat fy11,
 533                                 jfloat dx21, jfloat dy21,
 534                                 jfloat dx12, jfloat dy12)
 535 {
 536     //TODO
 537     J2dTraceNotImplPrimitive("MTLRenderer_FillAAParallelogram");
 538     DECLARE_MATRIX(om);
 539     // parameters for parallelogram bounding box
 540     jfloat bx11, by11, bx22, by22;
 541     // parameters for uv texture coordinates of parallelogram corners
 542     jfloat u11, v11, u12, v12, u21, v21, u22, v22;
 543 
 544     J2dTraceLn6(J2D_TRACE_INFO,
 545                 "MTLRenderer_FillAAParallelogram "
 546                 "(x=%6.2f y=%6.2f "
 547                 "dx1=%6.2f dy1=%6.2f "
 548                 "dx2=%6.2f dy2=%6.2f)",
 549                 fx11, fy11,
 550                 dx21, dy21,
 551                 dx12, dy12);
 552 
 553 }
 554 
 555 void
 556 MTLRenderer_FillAAParallelogramInnerOuter(MTLContext *mtlc, MTLSDOps *dstOps,
 557                                           jfloat ox11, jfloat oy11,
 558                                           jfloat ox21, jfloat oy21,
 559                                           jfloat ox12, jfloat oy12,
 560                                           jfloat ix11, jfloat iy11,
 561                                           jfloat ix21, jfloat iy21,
 562                                           jfloat ix12, jfloat iy12)
 563 {
 564     //TODO
 565     J2dTraceNotImplPrimitive("MTLRenderer_FillAAParallelogramInnerOuter");
 566 }
 567 
 568 void
 569 MTLRenderer_DrawAAParallelogram(MTLContext *mtlc, BMTLSDOps *dstOps,
 570                                 jfloat fx11, jfloat fy11,
 571                                 jfloat dx21, jfloat dy21,
 572                                 jfloat dx12, jfloat dy12,
 573                                 jfloat lwr21, jfloat lwr12)
 574 {
 575     //TODO
 576     J2dTraceNotImplPrimitive("MTLRenderer_DrawAAParallelogram");
 577     // dx,dy for line width in the "21" and "12" directions.
 578     jfloat ldx21, ldy21, ldx12, ldy12;
 579     // parameters for "outer" parallelogram
 580     jfloat ofx11, ofy11, odx21, ody21, odx12, ody12;
 581     // parameters for "inner" parallelogram
 582     jfloat ifx11, ify11, idx21, idy21, idx12, idy12;
 583 
 584     J2dTraceLn8(J2D_TRACE_INFO,
 585                 "MTLRenderer_DrawAAParallelogram "
 586                 "(x=%6.2f y=%6.2f "
 587                 "dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
 588                 "dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
 589                 fx11, fy11,
 590                 dx21, dy21, lwr21,
 591                 dx12, dy12, lwr12);
 592 
 593 }
 594 
 595 void
 596 MTLRenderer_EnableAAParallelogramProgram()
 597 {
 598     //TODO
 599     J2dTraceNotImplPrimitive("MTLRenderer_EnableAAParallelogramProgram");
 600     J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_EnableAAParallelogramProgram");
 601 }
 602 
 603 void
 604 MTLRenderer_DisableAAParallelogramProgram()
 605 {
 606     //TODO
 607     J2dTraceNotImplPrimitive("MTLRenderer_DisableAAParallelogramProgram");
 608     J2dTraceLn(J2D_TRACE_INFO, "MTLRenderer_DisableAAParallelogramProgram");
 609 }
 610 
 611 #endif /* !HEADLESS */