src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBufImgOps.m
branchmetal-prototype-branch
changeset 57416 e153174dba06
child 57472 5c986f86899e
equal deleted inserted replaced
57400:978ffc56771f 57416:e153174dba06
       
     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 
       
    30 #include "MTLBufImgOps.h"
       
    31 #include "MTLContext.h"
       
    32 #include "MTLRenderQueue.h"
       
    33 #include "MTLSurfaceDataBase.h"
       
    34 #include "GraphicsPrimitiveMgr.h"
       
    35 
       
    36 /** Evaluates to true if the given bit is set on the local flags variable. */
       
    37 #define IS_SET(flagbit) \
       
    38     (((flags) & (flagbit)) != 0)
       
    39 
       
    40 /**************************** ConvolveOp support ****************************/
       
    41 
       
    42 /**
       
    43  * The ConvolveOp shader is fairly straightforward.  For each texel in
       
    44  * the source texture, the shader samples the MxN texels in the surrounding
       
    45  * area, multiplies each by its corresponding kernel value, and then sums
       
    46  * them all together to produce a single color result.  Finally, the
       
    47  * resulting value is multiplied by the current OpenGL color, which contains
       
    48  * the extra alpha value.
       
    49  *
       
    50  * Note that this shader source code includes some "holes" marked by "%s".
       
    51  * This allows us to build different shader programs (e.g. one for
       
    52  * 3x3, one for 5x5, and so on) simply by filling in these "holes" with
       
    53  * a call to sprintf().  See the MTLBufImgOps_CreateConvolveProgram() method
       
    54  * for more details.
       
    55  *
       
    56  * REMIND: Currently this shader (and the supporting code in the
       
    57  *         EnableConvolveOp() method) only supports 3x3 and 5x5 filters.
       
    58  *         Early shader-level hardware did not support non-constant sized
       
    59  *         arrays but modern hardware should support them (although I
       
    60  *         don't know of any simple way to find out, other than to compile
       
    61  *         the shader at runtime and see if the drivers complain).
       
    62  */
       
    63 static const char *convolveShaderSource =
       
    64     // maximum size supported by this shader
       
    65     "const int MAX_KERNEL_SIZE = %s;"
       
    66     // image to be convolved
       
    67     "uniform sampler%s baseImage;"
       
    68     // image edge limits:
       
    69     //   imgEdge.xy = imgMin.xy (anything < will be treated as edge case)
       
    70     //   imgEdge.zw = imgMax.xy (anything > will be treated as edge case)
       
    71     "uniform vec4 imgEdge;"
       
    72     // value for each location in the convolution kernel:
       
    73     //   kernelVals[i].x = offsetX[i]
       
    74     //   kernelVals[i].y = offsetY[i]
       
    75     //   kernelVals[i].z = kernel[i]
       
    76     "uniform vec3 kernelVals[MAX_KERNEL_SIZE];"
       
    77     ""
       
    78     "void main(void)"
       
    79     "{"
       
    80     "    int i;"
       
    81     "    vec4 sum;"
       
    82     ""
       
    83     "    if (any(lessThan(gl_TexCoord[0].st, imgEdge.xy)) ||"
       
    84     "        any(greaterThan(gl_TexCoord[0].st, imgEdge.zw)))"
       
    85     "    {"
       
    86              // (placeholder for edge condition code)
       
    87     "        %s"
       
    88     "    } else {"
       
    89     "        sum = vec4(0.0);"
       
    90     "        for (i = 0; i < MAX_KERNEL_SIZE; i++) {"
       
    91     "            sum +="
       
    92     "                kernelVals[i].z *"
       
    93     "                texture%s(baseImage,"
       
    94     "                          gl_TexCoord[0].st + kernelVals[i].xy);"
       
    95     "        }"
       
    96     "    }"
       
    97     ""
       
    98          // modulate with gl_Color in order to apply extra alpha
       
    99     "    gl_FragColor = sum * gl_Color;"
       
   100     "}";
       
   101 
       
   102 /**
       
   103  * Flags that can be bitwise-or'ed together to control how the shader
       
   104  * source code is generated.
       
   105  */
       
   106 #define CONVOLVE_RECT            (1 << 0)
       
   107 #define CONVOLVE_EDGE_ZERO_FILL  (1 << 1)
       
   108 #define CONVOLVE_5X5             (1 << 2)
       
   109 
       
   110 /**
       
   111  * The handles to the ConvolveOp fragment program objects.  The index to
       
   112  * the array should be a bitwise-or'ing of the CONVOLVE_* flags defined
       
   113  * above.  Note that most applications will likely need to initialize one
       
   114  * or two of these elements, so the array is usually sparsely populated.
       
   115  */
       
   116 static GLhandleARB convolvePrograms[8];
       
   117 
       
   118 /**
       
   119  * The maximum kernel size supported by the ConvolveOp shader.
       
   120  */
       
   121 #define MAX_KERNEL_SIZE 25
       
   122 
       
   123 /**
       
   124  * Compiles and links the ConvolveOp shader program.  If successful, this
       
   125  * function returns a handle to the newly created shader program; otherwise
       
   126  * returns 0.
       
   127  */
       
   128 static GLhandleARB
       
   129 MTLBufImgOps_CreateConvolveProgram(jint flags)
       
   130 {
       
   131     //TODO
       
   132     return NULL;
       
   133 }
       
   134 
       
   135 void
       
   136 MTLBufImgOps_EnableConvolveOp(MTLContext *mtlc, jlong pSrcOps,
       
   137                               jboolean edgeZeroFill,
       
   138                               jint kernelWidth, jint kernelHeight,
       
   139                               unsigned char *kernel)
       
   140 {
       
   141     //TODO
       
   142 }
       
   143 
       
   144 void
       
   145 MTLBufImgOps_DisableConvolveOp(MTLContext *mtlc)
       
   146 {
       
   147     //TODO
       
   148     J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_DisableConvolveOp");
       
   149 }
       
   150 
       
   151 /**************************** RescaleOp support *****************************/
       
   152 
       
   153 /**
       
   154  * The RescaleOp shader is one of the simplest possible.  Each fragment
       
   155  * from the source image is multiplied by the user's scale factor and added
       
   156  * to the user's offset value (these are component-wise operations).
       
   157  * Finally, the resulting value is multiplied by the current OpenGL color,
       
   158  * which contains the extra alpha value.
       
   159  *
       
   160  * The RescaleOp spec says that the operation is performed regardless of
       
   161  * whether the source data is premultiplied or non-premultiplied.  This is
       
   162  * a problem for the OpenGL pipeline in that a non-premultiplied
       
   163  * BufferedImage will have already been converted into premultiplied
       
   164  * when uploaded to an OpenGL texture.  Therefore, we have a special mode
       
   165  * called RESCALE_NON_PREMULT (used only for source images that were
       
   166  * originally non-premultiplied) that un-premultiplies the source color
       
   167  * prior to the rescale operation, then re-premultiplies the resulting
       
   168  * color before returning from the fragment shader.
       
   169  *
       
   170  * Note that this shader source code includes some "holes" marked by "%s".
       
   171  * This allows us to build different shader programs (e.g. one for
       
   172  * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on)
       
   173  * simply by filling in these "holes" with a call to sprintf().  See the
       
   174  * MTLBufImgOps_CreateRescaleProgram() method for more details.
       
   175  */
       
   176 static const char *rescaleShaderSource =
       
   177     // image to be rescaled
       
   178     "uniform sampler%s baseImage;"
       
   179     // vector containing scale factors
       
   180     "uniform vec4 scaleFactors;"
       
   181     // vector containing offsets
       
   182     "uniform vec4 offsets;"
       
   183     ""
       
   184     "void main(void)"
       
   185     "{"
       
   186     "    vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);"
       
   187          // (placeholder for un-premult code)
       
   188     "    %s"
       
   189          // rescale source value
       
   190     "    vec4 result = (srcColor * scaleFactors) + offsets;"
       
   191          // (placeholder for re-premult code)
       
   192     "    %s"
       
   193          // modulate with gl_Color in order to apply extra alpha
       
   194     "    gl_FragColor = result * gl_Color;"
       
   195     "}";
       
   196 
       
   197 /**
       
   198  * Flags that can be bitwise-or'ed together to control how the shader
       
   199  * source code is generated.
       
   200  */
       
   201 #define RESCALE_RECT        (1 << 0)
       
   202 #define RESCALE_NON_PREMULT (1 << 1)
       
   203 
       
   204 /**
       
   205  * The handles to the RescaleOp fragment program objects.  The index to
       
   206  * the array should be a bitwise-or'ing of the RESCALE_* flags defined
       
   207  * above.  Note that most applications will likely need to initialize one
       
   208  * or two of these elements, so the array is usually sparsely populated.
       
   209  */
       
   210 static GLhandleARB rescalePrograms[4];
       
   211 
       
   212 /**
       
   213  * Compiles and links the RescaleOp shader program.  If successful, this
       
   214  * function returns a handle to the newly created shader program; otherwise
       
   215  * returns 0.
       
   216  */
       
   217 static GLhandleARB
       
   218 MTLBufImgOps_CreateRescaleProgram(jint flags)
       
   219 {
       
   220     //TODO
       
   221     return NULL;
       
   222 }
       
   223 
       
   224 void
       
   225 MTLBufImgOps_EnableRescaleOp(MTLContext *mtlc, jlong pSrcOps,
       
   226                              jboolean nonPremult,
       
   227                              unsigned char *scaleFactors,
       
   228                              unsigned char *offsets)
       
   229 {
       
   230     //TODO
       
   231 }
       
   232 
       
   233 void
       
   234 MTLBufImgOps_DisableRescaleOp(MTLContext *mtlc)
       
   235 {
       
   236     //TODO
       
   237     J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_DisableRescaleOp");
       
   238     RETURN_IF_NULL(mtlc);
       
   239 }
       
   240 
       
   241 /**************************** LookupOp support ******************************/
       
   242 
       
   243 /**
       
   244  * The LookupOp shader takes a fragment color (from the source texture) as
       
   245  * input, subtracts the optional user offset value, and then uses the
       
   246  * resulting value to index into the lookup table texture to provide
       
   247  * a new color result.  Finally, the resulting value is multiplied by
       
   248  * the current OpenGL color, which contains the extra alpha value.
       
   249  *
       
   250  * The lookup step requires 3 texture accesses (or 4, when alpha is included),
       
   251  * which is somewhat unfortunate because it's not ideal from a performance
       
   252  * standpoint, but that sort of thing is getting faster with newer hardware.
       
   253  * In the 3-band case, we could consider using a three-dimensional texture
       
   254  * and performing the lookup with a single texture access step.  We already
       
   255  * use this approach in the LCD text shader, and it works well, but for the
       
   256  * purposes of this LookupOp shader, it's probably overkill.  Also, there's
       
   257  * a difference in that the LCD text shader only needs to populate the 3D LUT
       
   258  * once, but here we would need to populate it on every invocation, which
       
   259  * would likely be a waste of VRAM and CPU/GPU cycles.
       
   260  *
       
   261  * The LUT texture is currently hardcoded as 4 rows/bands, each containing
       
   262  * 256 elements.  This means that we currently only support user-provided
       
   263  * tables with no more than 256 elements in each band (this is checked at
       
   264  * at the Java level).  If the user provides a table with less than 256
       
   265  * elements per band, our shader will still work fine, but if elements are
       
   266  * accessed with an index >= the size of the LUT, then the shader will simply
       
   267  * produce undefined values.  Typically the user would provide an offset
       
   268  * value that would prevent this from happening, but it's worth pointing out
       
   269  * this fact because the software LookupOp implementation would usually
       
   270  * throw an ArrayIndexOutOfBoundsException in this scenario (although it is
       
   271  * not something demanded by the spec).
       
   272  *
       
   273  * The LookupOp spec says that the operation is performed regardless of
       
   274  * whether the source data is premultiplied or non-premultiplied.  This is
       
   275  * a problem for the OpenGL pipeline in that a non-premultiplied
       
   276  * BufferedImage will have already been converted into premultiplied
       
   277  * when uploaded to an OpenGL texture.  Therefore, we have a special mode
       
   278  * called LOOKUP_NON_PREMULT (used only for source images that were
       
   279  * originally non-premultiplied) that un-premultiplies the source color
       
   280  * prior to the lookup operation, then re-premultiplies the resulting
       
   281  * color before returning from the fragment shader.
       
   282  *
       
   283  * Note that this shader source code includes some "holes" marked by "%s".
       
   284  * This allows us to build different shader programs (e.g. one for
       
   285  * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on)
       
   286  * simply by filling in these "holes" with a call to sprintf().  See the
       
   287  * MTLBufImgOps_CreateLookupProgram() method for more details.
       
   288  */
       
   289 static const char *lookupShaderSource =
       
   290     // source image (bound to texture unit 0)
       
   291     "uniform sampler%s baseImage;"
       
   292     // lookup table (bound to texture unit 1)
       
   293     "uniform sampler2D lookupTable;"
       
   294     // offset subtracted from source index prior to lookup step
       
   295     "uniform vec4 offset;"
       
   296     ""
       
   297     "void main(void)"
       
   298     "{"
       
   299     "    vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);"
       
   300          // (placeholder for un-premult code)
       
   301     "    %s"
       
   302          // subtract offset from original index
       
   303     "    vec4 srcIndex = srcColor - offset;"
       
   304          // use source value as input to lookup table (note that
       
   305          // "v" texcoords are hardcoded to hit texel centers of
       
   306          // each row/band in texture)
       
   307     "    vec4 result;"
       
   308     "    result.r = texture2D(lookupTable, vec2(srcIndex.r, 0.125)).r;"
       
   309     "    result.g = texture2D(lookupTable, vec2(srcIndex.g, 0.375)).r;"
       
   310     "    result.b = texture2D(lookupTable, vec2(srcIndex.b, 0.625)).r;"
       
   311          // (placeholder for alpha store code)
       
   312     "    %s"
       
   313          // (placeholder for re-premult code)
       
   314     "    %s"
       
   315          // modulate with gl_Color in order to apply extra alpha
       
   316     "    gl_FragColor = result * gl_Color;"
       
   317     "}";
       
   318 
       
   319 /**
       
   320  * Flags that can be bitwise-or'ed together to control how the shader
       
   321  * source code is generated.
       
   322  */
       
   323 #define LOOKUP_RECT          (1 << 0)
       
   324 #define LOOKUP_USE_SRC_ALPHA (1 << 1)
       
   325 #define LOOKUP_NON_PREMULT   (1 << 2)
       
   326 
       
   327 /**
       
   328  * The handles to the LookupOp fragment program objects.  The index to
       
   329  * the array should be a bitwise-or'ing of the LOOKUP_* flags defined
       
   330  * above.  Note that most applications will likely need to initialize one
       
   331  * or two of these elements, so the array is usually sparsely populated.
       
   332  */
       
   333 static GLhandleARB lookupPrograms[8];
       
   334 
       
   335 /**
       
   336  * The handle to the lookup table texture object used by the shader.
       
   337  */
       
   338 static GLuint lutTextureID = 0;
       
   339 
       
   340 /**
       
   341  * Compiles and links the LookupOp shader program.  If successful, this
       
   342  * function returns a handle to the newly created shader program; otherwise
       
   343  * returns 0.
       
   344  */
       
   345 static GLhandleARB
       
   346 MTLBufImgOps_CreateLookupProgram(jint flags)
       
   347 {
       
   348     //TODO
       
   349 
       
   350     return NULL;
       
   351 }
       
   352 
       
   353 void
       
   354 MTLBufImgOps_EnableLookupOp(MTLContext *mtlc, jlong pSrcOps,
       
   355                             jboolean nonPremult, jboolean shortData,
       
   356                             jint numBands, jint bandLength, jint offset,
       
   357                             void *tableValues)
       
   358 {
       
   359     //TODO
       
   360 }
       
   361 
       
   362 void
       
   363 MTLBufImgOps_DisableLookupOp(MTLContext *mtlc)
       
   364 {
       
   365     //TODO
       
   366     J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_DisableLookupOp");
       
   367 }
       
   368 
       
   369 #endif /* !HEADLESS */