OpenJDK / lanai / lanai
changeset 56589:a1fc001392fd
8233039: support different raster formats (for SwToTexture blit)
* supported flag SurfaceData.isOpaue
* added implementation for missing composite rules (some combinations of parameters and extra-alpha can't be supported with CAD-multipliers, need to reimplement via shaders)
author | abochkarev |
---|---|
date | Fri, 01 Nov 2019 17:25:07 +0300 |
parents | b87de4164e02 |
children | 49c8cbf9d3b9 |
files | src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLContext.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.h src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.m src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.m |
diffstat | 5 files changed, 340 insertions(+), 55 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m Fri Nov 01 17:23:42 2019 +0300 +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLBlitLoops.m Fri Nov 01 17:25:07 2019 +0300 @@ -39,7 +39,58 @@ #include <string.h> // memcpy #include "IntArgbPre.h" -extern MTLPixelFormat PixelFormats[]; +#import <Accelerate/Accelerate.h> + +typedef struct { + MTLPixelFormat format; + jboolean hasAlpha; + jboolean isPremult; + const uint8_t * permuteMap; + +} MTLRasterFormatInfo; + +// 0 denotes the alpha channel, 1 the red channel, 2 the green channel, and 3 the blue channel. +const uint8_t permuteMap_rgbx[4] = { 1, 2, 3, 0 }; +const uint8_t permuteMap_bgrx[4] = { 3, 2, 1, 0 }; + +static uint8_t revertPerm(const uint8_t * perm, uint8_t pos) { + for (int c = 0; c < 4; ++c) { + if (perm[c] == pos) + return c; + } + return -1; +} + +#define uint2swizzle(channel) (channel == 0 ? MTLTextureSwizzleAlpha : (channel == 1 ? MTLTextureSwizzleRed : (channel == 2 ? MTLTextureSwizzleGreen : (channel == 3 ? MTLTextureSwizzleBlue : MTLTextureSwizzleZero)))) + +/** + * This table contains the "pixel formats" for all system memory surfaces + * that Metal is capable of handling, indexed by the "PF_" constants defined + * in MTLLSurfaceData.java. These pixel formats contain information that is + * passed to Metal when copying from a system memory ("Sw") surface to + * an Metal surface + */ +MTLRasterFormatInfo RasterFormatInfos[] = { + { MTLPixelFormatBGRA8Unorm, 1, 0, NULL }, /* 0 - IntArgb */ // Argb (in java notation) + { MTLPixelFormatBGRA8Unorm, 1, 1, NULL }, /* 1 - IntArgbPre */ + { MTLPixelFormatBGRA8Unorm, 0, 1, NULL }, /* 2 - IntRgb */ // xrgb + { MTLPixelFormatBGRA8Unorm, 0, 1, permuteMap_rgbx }, /* 3 - IntRgbx */ + { MTLPixelFormatRGBA8Unorm, 0, 1, NULL }, /* 4 - IntBgr */ // xbgr + { MTLPixelFormatBGRA8Unorm, 0, 1, permuteMap_bgrx }, /* 5 - IntBgrx */ + +// TODO: support 2-byte formats +// { GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, +// 2, 0, 1, }, /* 7 - Ushort555Rgb */ +// { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, +// 2, 0, 1, }, /* 8 - Ushort555Rgbx*/ +// { GL_LUMINANCE, GL_UNSIGNED_BYTE, +// 1, 0, 1, }, /* 9 - ByteGray */ +// { GL_LUMINANCE, GL_UNSIGNED_SHORT, +// 2, 0, 1, }, /*10 - UshortGray */ +// { GL_BGR, GL_UNSIGNED_BYTE, +// 1, 0, 1, }, /*11 - ThreeByteBgr */ +}; + extern void J2dTraceImpl(int level, jboolean cr, const char *string, ...); void fillTxQuad( @@ -106,22 +157,23 @@ static void drawTex2Tex(MTLContext *mtlc, id<MTLTexture> src, id<MTLTexture> dst, - jboolean rtt, jint hint, + jboolean isSrcOpaque, jboolean isDstOpaque, jint sx1, jint sy1, jint sx2, jint sy2, jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2) { if (mtlc == NULL || src == nil || dst == nil) return; -// J2dTraceLn2(J2D_TRACE_VERBOSE, "_drawTex2Tex: src tex=%p, dst tex=%p", src, dst); +// J2dTraceLn2(J2D_TRACE_VERBOSE, "drawTex2Tex: src tex=%p, dst tex=%p", src, dst); // J2dTraceLn4(J2D_TRACE_VERBOSE, " sw=%d sh=%d dw=%d dh=%d", src.width, src.height, dst.width, dst.height); // J2dTraceLn4(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d", sx1, sy1, sx2, sy2); // J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f", dx1, dy1, dx2, dy2); - id<MTLRenderCommandEncoder> encoder = [mtlc createCommonSamplingEncoderForDest:dst]; + id<MTLRenderCommandEncoder> encoder = [mtlc createCommonSamplingEncoderForDest: + dst + isSrcOpaque:isSrcOpaque + isDstOpaque:isDstOpaque]; - - const jboolean normalize = !mtlc.useTransform; struct TxtVertex quadTxVerticesBuffer[6]; fillTxQuad(quadTxVerticesBuffer, sx1, sy1, sx2, sy2, src.width, src.height, dx1, dy1, dx2, dy2, dst.width, dst.height); @@ -154,24 +206,85 @@ J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_IsoBlit [via sampling]: bsrc=%p [tex=%p], bdst=%p [tex=%p] | s (%dx%d) -> d (%dx%d) | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", srcOps, srcOps->pTexture, dstOps, dstOps->pTexture, srcTex.width, srcTex.height, dstOps->width, dstOps->height, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); #endif //DEBUG - drawTex2Tex(mtlc, srcOps->pTexture, dstOps->pTexture, rtt, hint, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); + drawTex2Tex(mtlc, srcOps->pTexture, dstOps->pTexture, srcOps->isOpaque, dstOps->isOpaque, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); +} + +static +id<MTLTexture> replaceTextureRegion(id<MTLTexture> dest, const SurfaceDataRasInfo * srcInfo, const MTLRasterFormatInfo * rfi, int sx1, int sy1, int sx2, int sy2) { + const int sw = sx2 - sx1; + const int sh = sy2 - sy1; + + const void * raster = srcInfo->rasBase; + if (rfi->permuteMap != NULL) { + if (@available(macOS 10.15, *)) { + const uint8_t swzRed = revertPerm(rfi->permuteMap, 1); + const uint8_t swzGreen = revertPerm(rfi->permuteMap, 2); + const uint8_t swzBlue = revertPerm(rfi->permuteMap, 3); + const uint8_t swzAlpha = revertPerm(rfi->permuteMap, 0); + MTLTextureSwizzleChannels swizzle = MTLTextureSwizzleChannelsMake( + uint2swizzle(swzRed), + uint2swizzle(swzGreen), + uint2swizzle(swzBlue), + rfi->hasAlpha ? uint2swizzle(swzAlpha) : MTLTextureSwizzleOne + ); + dest = [dest + newTextureViewWithPixelFormat:MTLPixelFormatBGRA8Unorm + textureType:MTLTextureType2D + levels:NSMakeRange(0, 1) slices:NSMakeRange(0, 1) + swizzle:swizzle]; + J2dTraceLn5(J2D_TRACE_VERBOSE, "replaceTextureRegion [use swizzle for pooled]: %d, %d, %d, %d, hasA=%d", + swizzle.red, swizzle.green, swizzle.blue, swizzle.alpha, rfi->hasAlpha); + } else { + // perform raster conversion + // invoked only from rq-thread, so use static buffers + // but it's better to use thread-local buffers (or special buffer manager) + const int destRasterSize = sw*sh*4; + + static int bufferSize = 0; + static void * buffer = NULL; + if (buffer == NULL || bufferSize < destRasterSize) { + bufferSize = destRasterSize; + buffer = realloc(buffer, bufferSize); + } + if (buffer == NULL) { + J2dTraceLn1(J2D_TRACE_ERROR, "replaceTextureRegion: can't alloc buffer for raster conversion, size=%d", bufferSize); + bufferSize = 0; + return nil; + } + vImage_Buffer src; + src.height = sw; + src.width = sh; + src.rowBytes = srcInfo->scanStride; + src.data = srcInfo->rasBase; + + vImage_Buffer dest; + dest.height = sw; + dest.width = sh; + dest.rowBytes = sw*4; + dest.data = buffer; + + vImagePermuteChannels_ARGB8888(&src, &dest, rfi->permuteMap, kvImageNoFlags); + raster = buffer; + + J2dTraceLn5(J2D_TRACE_VERBOSE, "replaceTextureRegion [use conversion]: %d, %d, %d, %d, hasA=%d", + rfi->permuteMap[0], rfi->permuteMap[1], rfi->permuteMap[2], rfi->permuteMap[3], rfi->hasAlpha); + } + } + + MTLRegion region = MTLRegionMake2D(sx1, sy1, sw, sh); + [dest replaceRegion:region mipmapLevel:0 withBytes:raster bytesPerRow:srcInfo->scanStride]; + return dest; } /** * Inner loop used for copying a source system memory ("Sw") surface to a * destination MTL "Surface". This method is invoked from * MTLBlitLoops_Blit(). - * - * The standard glDrawPixels() mechanism is used to copy the source region - * into the destination region. If the regions have different - * dimensions, the source will be scaled into the destination - * as appropriate (only nearest neighbor filtering will be applied for simple - * scale operations). */ static void MTLBlitSwToSurfaceViaTexture(MTLContext *ctx, SurfaceDataRasInfo *srcInfo, BMTLSDOps * bmtlsdOps, - MTPixelFormat *pf, + MTLRasterFormatInfo * rfi, jint sx1, jint sy1, jint sx2, jint sy2, jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2) { @@ -188,15 +301,14 @@ J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_Blit [via pooled texture]: bdst=%p [tex=%p], sw=%d, sh=%d | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", bmtlsdOps, dest, sw, sh, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); #endif //DEBUG - id<MTLTexture> texBuff = [ctx.texturePool getTexture:sw height:sh format:MTLPixelFormatBGRA8Unorm]; + id<MTLTexture> texBuff = [ctx.texturePool getTexture:sw height:sh format:rfi->format]; if (texBuff == nil) { J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitSwToSurfaceViaTexture: can't obtain temporary texture object from pool"); return; } - MTLRegion region = MTLRegionMake2D(0, 0, sw, sh); - [texBuff replaceRegion:region mipmapLevel:0 withBytes:srcInfo->rasBase bytesPerRow:srcInfo->scanStride]; // texBuff is locked for current frame - drawTex2Tex(ctx, texBuff, dest, 0, 0, 0, 0, sw, sh, dx1, dy1, dx2, dy2); + texBuff = replaceTextureRegion(texBuff, srcInfo, rfi, sx1, sy1, sx2, sy2); // texBuff is locked for current frame + drawTex2Tex(ctx, texBuff, dest, !rfi->hasAlpha, bmtlsdOps->isOpaque, 0, 0, sw, sh, dx1, dy1, dx2, dy2); } /** @@ -365,12 +477,17 @@ SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps); BMTLSDOps *dstOps = (BMTLSDOps *)jlong_to_ptr(pDstOps); SurfaceDataRasInfo srcInfo; - MTLPixelFormat pf = MTLPixelFormatBGRA8Unorm;//PixelFormats[srctype]; if (dstOps == NULL || dstOps->pTexture == NULL) { J2dTraceLn(J2D_TRACE_ERROR, "MTLBlitLoops_Blit: dest is null"); return; } + if (srctype >= sizeof(RasterFormatInfos)/ sizeof(MTLRasterFormatInfo)) { + J2dTraceLn1(J2D_TRACE_ERROR, "MTLBlitLoops_Blit: source pixel format %d isn't supported", srctype); + return; + } + + MTLRasterFormatInfo rfi = RasterFormatInfos[srctype]; id<MTLTexture> dest = dstOps->pTexture; if (dx1 < 0) { sx1 += dx1; @@ -408,7 +525,7 @@ return; } - J2dTraceLn5(J2D_TRACE_VERBOSE, "MTLBlitLoops_Blit: pf=%d texture=%d srctype=%d xform=%d hint=%d", pf, texture, srctype, xform, hint); + J2dTraceLn4(J2D_TRACE_VERBOSE, "MTLBlitLoops_Blit: texture=%d srctype=%d xform=%d hint=%d", texture, srctype, xform, hint); if (srcInfo.bounds.x2 > srcInfo.bounds.x1 && srcInfo.bounds.y2 > srcInfo.bounds.y1) { srcOps->GetRasInfo(env, srcOps, &srcInfo); @@ -436,13 +553,13 @@ && fabs(dx2 - dx1 - sx2 + sx1) < 0.001f && fabs(dy2 - dy1 - sy2 + sy1) < 0.001f // dimensions are equal (TODO: check that dx1,dy1 is integer) && !mtlc.useTransform); // TODO: check whether transform is simple translate (and use replaceRegion in this case) if (useReplaceRegion) { - MTLRegion region = MTLRegionMake2D(dx1, dy1, dx2 - dx1, dy2 - dy1); #ifdef DEBUG J2dTraceImpl(J2D_TRACE_VERBOSE, JNI_TRUE, "MTLBlitLoops_Blit [replaceRegion]: bdst=%p [tex=%p] %dx%d | src (%d, %d, %d, %d) -> dst (%1.2f, %1.2f, %1.2f, %1.2f)", dstOps, dest, dest.width, dest.height, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); #endif //DEBUG - [dest replaceRegion:region mipmapLevel:0 withBytes:srcInfo.rasBase bytesPerRow:srcInfo.scanStride]; // executed at CPU (sync), TODO: lock dest for current frame + replaceTextureRegion(dest, &srcInfo, &rfi, (int)dx1, (int)dy1, (int)dx2, (int)dy2); + dstOps->isOpaque = !rfi.hasAlpha; } else { - MTLBlitSwToSurfaceViaTexture(mtlc, &srcInfo, dstOps, &pf, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); + MTLBlitSwToSurfaceViaTexture(mtlc, &srcInfo, dstOps, &rfi, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); } } SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
--- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLContext.m Fri Nov 01 17:23:42 2019 +0300 +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLContext.m Fri Nov 01 17:25:07 2019 +0300 @@ -370,7 +370,12 @@ [self setEncoderTransform:encoder dest:dest]; } -- (void) updateSamplingEncoderProperties:(id<MTLRenderCommandEncoder>) encoder dest:(id<MTLTexture>) dest { +- (void) updateSamplingEncoderProperties: + (id<MTLRenderCommandEncoder>) encoder + dest:(id<MTLTexture>) dest + isSrcOpaque:(bool)isSrcOpaque + isDstOpaque:(bool)isDstOpaque +{ if (compState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) { struct TxtFrameUniforms uf = {RGBA_TO_V4(color), 1}; [encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer]; @@ -378,7 +383,11 @@ struct TxtFrameUniforms uf = {RGBA_TO_V4(0), 0}; [encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer]; } - [encoder setRenderPipelineState:[pipelineStateStorage getTexturePipelineState:NO compositeRule:alphaCompositeRule]]; + [encoder setRenderPipelineState:[pipelineStateStorage getTexturePipelineState:NO + isDestPremultiplied:NO + isSrcOpaque:isSrcOpaque + isDstOpaque:isDstOpaque + compositeRule:alphaCompositeRule]]; [self setEncoderTransform:encoder dest:dest]; } @@ -394,12 +403,15 @@ return commonRenderEncoder; } -- (id<MTLRenderCommandEncoder>)createCommonSamplingEncoderForDest:(id<MTLTexture>)dest { +- (id<MTLRenderCommandEncoder>)createCommonSamplingEncoderForDest:(id<MTLTexture>)dest isSrcOpaque:(bool)isSrcOpaque isDstOpaque:(bool)isDstOpaque { if (commonRenderEncoder == nil) { commonRenderEncoder = [self createEncoderForDest: dest]; } [self updateRenderEncoderProperties:commonRenderEncoder dest:dest]; - [self updateSamplingEncoderProperties:commonRenderEncoder dest:dest]; + [self updateSamplingEncoderProperties:commonRenderEncoder + dest:dest + isSrcOpaque:isSrcOpaque + isDstOpaque:isDstOpaque]; return commonRenderEncoder; }
--- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.h Fri Nov 01 17:23:42 2019 +0300 +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.h Fri Nov 01 17:25:07 2019 +0300 @@ -23,7 +23,11 @@ - (id) initWithDevice:(id<MTLDevice>)device shaderLibPath:(NSString *)shadersLib; - (id<MTLRenderPipelineState>) getRenderPipelineState:(bool)isGradient; -- (id<MTLRenderPipelineState>) getTexturePipelineState:(bool)isSourcePremultiplied compositeRule:(int)compositeRule; +- (id<MTLRenderPipelineState>) getTexturePipelineState:(bool)isSourcePremultiplied + isDestPremultiplied:(bool)isDestPremultiplied + isSrcOpaque:(bool)isSrcOpaque + isDstOpaque:(bool)isDstOpaque + compositeRule:(int)compositeRule; - (id<MTLFunction>) getShader:(NSString *)name; @end
--- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.m Fri Nov 01 17:23:42 2019 +0300 +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLPipelineStatesStorage.m Fri Nov 01 17:25:07 2019 +0300 @@ -4,6 +4,13 @@ #include "GraphicsPrimitiveMgr.h" #import "common.h" +static void setBlendingFactors(MTLRenderPipelineColorAttachmentDescriptor * cad, + int compositeRule, + bool isSourcePremultiplied, + bool isDestPremultiplied, + bool isSrcOpaque, + bool isDstOpaque); + @implementation MTLPipelineStatesStorage @synthesize device; @@ -56,8 +63,6 @@ { // pre-create main states [self getRenderPipelineState:YES]; [self getRenderPipelineState:NO]; - [self getTexturePipelineState:NO compositeRule:RULE_Src]; - [self getTexturePipelineState:NO compositeRule:RULE_SrcOver]; } return self; @@ -92,7 +97,12 @@ return result; }; -- (id<MTLRenderPipelineState>) getTexturePipelineState:(bool)isSourcePremultiplied compositeRule:(int)compositeRule { +- (id<MTLRenderPipelineState>) getTexturePipelineState:(bool)isSourcePremultiplied + isDestPremultiplied:(bool)isDestPremultiplied + isSrcOpaque:(bool)isSrcOpaque + isDstOpaque:(bool)isDstOpaque + compositeRule:(int)compositeRule +{ @autoreleasepool { NSString *uid = [NSString stringWithFormat:@"texture_compositeRule[%d]", compositeRule]; @@ -104,29 +114,12 @@ pipelineDesc.vertexFunction = vertexShader; pipelineDesc.fragmentFunction = fragmentShader; - if (compositeRule != RULE_Src) { - pipelineDesc.colorAttachments[0].blendingEnabled = YES; - - if (!isSourcePremultiplied) - pipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; - - //RGB = Source.rgb * SBF + Dest.rgb * DBF - //A = Source.a * SBF + Dest.a * DBF - // - //default SRC: - //DBF=0 - //SBF=1 - if (compositeRule == RULE_SrcOver) { - // SRC_OVER (Porter-Duff Source Over Destination rule): - // Ar = As + Ad*(1-As) - // Cr = Cs + Cd*(1-As) - pipelineDesc.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; - pipelineDesc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; - } else { - J2dTrace1(J2D_TRACE_ERROR, "Unimplemented composite rule %d (will be used Src)", compositeRule); - pipelineDesc.colorAttachments[0].blendingEnabled = NO; - } - } + setBlendingFactors( + pipelineDesc.colorAttachments[0], + compositeRule, + isSourcePremultiplied, isDestPremultiplied, + isSrcOpaque, isDstOpaque + ); NSError *error = nil; result = [[self.device newRenderPipelineStateWithDescriptor:pipelineDesc error:&error] autorelease]; @@ -151,3 +144,162 @@ return result; } @end + +static void setBlendingFactors( + MTLRenderPipelineColorAttachmentDescriptor * cad, + int compositeRule, + bool isSourcePremultiplied, + bool isDestPremultiplied, + bool isSrcOpaque, + bool isDstOpaque +) { + if (compositeRule == RULE_Src) { + J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_Src"); + return; + } + + cad.blendingEnabled = YES; + + // RGB = Source.rgb * SBFc + Dest.rgb * DBFc + // A = Source.a * SBFa + Dest.a * DBFa + // + // default mode == RULE_Src with constants: + // DBFa=0 + // DBFc=0 + // SBFa=1 + // SBFc=1 + // + // NOTE: constants MTLBlendFactorBlendAlpha, MTLBlendFactorOneMinusBlendAlpha refers to [encoder setBlendColorRed:green:blue:alpha:] (default value is zero) + // + // TODO: implement alpha-composite via shaders (will be much more simpler and can support all rules and modes) + + switch (compositeRule) { + case RULE_SrcOver: { + // Ar = As + Ad*(1-As) + // Cr = Cs + Cd*(1-As) + if (isSrcOpaque) { + J2dTraceLn(J2D_TRACE_VERBOSE, "rule=RULE_Src, but blending is disabled because src is opaque"); + cad.blendingEnabled = NO; + return; + } + if (isDstOpaque) { + J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_SrcOver with opaque dest isn't implemented (dst alpha won't be ignored)"); + } + if (!isSourcePremultiplied) { + cad.sourceRGBBlendFactor = MTLBlendFactorSourceAlpha; + } + cad.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + cad.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_SrcOver"); + break; + } + case RULE_DstOver: { + // Ar = As*(1-Ad) + Ad + // Cr = Cs*(1-Ad) + Cd + if (isSrcOpaque) { + J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_DstOver with opaque src isn't implemented (src alpha won't be ignored)"); + } + if (isDstOpaque) { + J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_DstOver with opaque dest hasn't any sense"); + } + if (!isSourcePremultiplied) { + J2dTrace(J2D_TRACE_ERROR, "Composite rule RULE_DstOver with non-premultiplied source isn't implemented (scr alpha will be ignored for rgb-component)"); + } + cad.sourceAlphaBlendFactor = MTLBlendFactorOneMinusDestinationAlpha; + cad.sourceRGBBlendFactor = MTLBlendFactorOneMinusDestinationAlpha; + cad.destinationAlphaBlendFactor = MTLBlendFactorOne; + cad.destinationRGBBlendFactor = MTLBlendFactorOne; + J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_DstOver"); + break; + } + case RULE_SrcIn: { + // Ar = As*Ad + // Cr = Cs*Ad + if (isSrcOpaque) { + J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_SrcIn with opaque src isn't implemented (src alpha won't be ignored)"); + } + if (isDstOpaque) { + J2dTraceLn(J2D_TRACE_VERBOSE, "rule=RULE_SrcIn, but blending is disabled because dest is opaque"); + cad.blendingEnabled = NO; + return; + } + if (!isSourcePremultiplied) { + J2dTrace(J2D_TRACE_ERROR, "Composite rule RULE_SrcIn with non-premultiplied source isn't implemented (scr alpha will be ignored for rgb-component)"); + } + cad.sourceAlphaBlendFactor = MTLBlendFactorDestinationAlpha; + cad.sourceRGBBlendFactor = MTLBlendFactorDestinationAlpha; + cad.destinationAlphaBlendFactor = MTLBlendFactorZero; + cad.destinationRGBBlendFactor = MTLBlendFactorZero; + J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_SrcIn"); + break; + } + case RULE_DstIn: { + // Ar = Ad*As + // Cr = Cd*As + if (isSrcOpaque) { + J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_DstIn with opaque src isn't implemented (src alpha won't be ignored)"); + } + if (isDstOpaque) { + J2dTraceLn(J2D_TRACE_ERROR, "Composite rule RULE_DstIn with opaque dest isn't implemented (dest alpha won't be ignored)"); + } + cad.sourceAlphaBlendFactor = MTLBlendFactorZero; + cad.sourceRGBBlendFactor = MTLBlendFactorZero; + cad.destinationAlphaBlendFactor = MTLBlendFactorSourceAlpha; + cad.destinationRGBBlendFactor = MTLBlendFactorSourceAlpha; + J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_DstIn"); + break; + } + case RULE_SrcOut: { + // Ar = As*(1-Ad) + // Cr = Cs*(1-Ad) + if (!isSourcePremultiplied) { + J2dTrace(J2D_TRACE_ERROR, "Composite rule SrcOut with non-premultiplied source isn't implemented (scr alpha will be ignored for rgb-component)"); + } + cad.sourceAlphaBlendFactor = MTLBlendFactorOneMinusDestinationAlpha; + cad.sourceRGBBlendFactor = MTLBlendFactorOneMinusDestinationAlpha; + cad.destinationAlphaBlendFactor = MTLBlendFactorZero; + cad.destinationRGBBlendFactor = MTLBlendFactorZero; + J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_SrcOut"); + break; + } + case RULE_DstOut: { + // Ar = Ad*(1-As) + // Cr = Cd*(1-As) + cad.sourceAlphaBlendFactor = MTLBlendFactorZero; + cad.sourceRGBBlendFactor = MTLBlendFactorZero; + cad.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + cad.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_DstOut"); + break; + } + case RULE_Xor: { + // Ar = As*(1-Ad) + Ad*(1-As) + // Cr = Cs*(1-Ad) + Cd*(1-As) + if (!isSourcePremultiplied) { + J2dTrace(J2D_TRACE_ERROR, "Composite rule Xor with non-premultiplied source isn't implemented (scr alpha will be ignored for rgb-component)"); + } + cad.sourceAlphaBlendFactor = MTLBlendFactorOneMinusDestinationAlpha; + cad.sourceRGBBlendFactor = MTLBlendFactorOneMinusDestinationAlpha; + cad.destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + cad.destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha; + J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_Xor"); + break; + } + case RULE_Clear: { + // Ar = 0 + // Cr = 0 + cad.sourceAlphaBlendFactor = MTLBlendFactorZero; + cad.sourceRGBBlendFactor = MTLBlendFactorZero; + cad.destinationAlphaBlendFactor = MTLBlendFactorZero; + cad.destinationRGBBlendFactor = MTLBlendFactorZero; + J2dTraceLn(J2D_TRACE_VERBOSE, "set RULE_Clear"); + break; + } + + default: { + J2dTrace1(J2D_TRACE_ERROR, "Unimplemented composite rule %d (will be used Src)", compositeRule); + cad.blendingEnabled = NO; + } + } + +} \ No newline at end of file
--- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.m Fri Nov 01 17:23:42 2019 +0300 +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLVertexCache.m Fri Nov 01 17:25:07 2019 +0300 @@ -223,7 +223,7 @@ void MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps) { J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_CreateSamplingEncoder"); - encoder = [mtlc createCommonSamplingEncoderForDest:dstOps->pTexture]; + encoder = [mtlc createCommonSamplingEncoderForDest:dstOps->pTexture isSrcOpaque:NO isDstOpaque:NO]; } void