266 filter:(jboolean)filter
267 xp0:(jdouble)xp0
268 xp1:(jdouble)xp1
269 xp3:(jdouble)xp3
270 yp0:(jdouble)yp0
271 yp1:(jdouble)yp1
272 yp3:(jdouble)yp3
273 {
274 _paintState = sun_java2d_SunGraphics2D_PAINT_TEXTURE;
275 _paintTexture = textureID;
276
277 _anchor.xParams[0] = xp0;
278 _anchor.xParams[1] = xp1;
279 _anchor.xParams[2] = xp3;
280
281 _anchor.yParams[0] = yp0;
282 _anchor.yParams[1] = yp1;
283 _anchor.yParams[2] = yp3;
284 }
285
286 static id<MTLSamplerState> samplerNearestClamp = nil;
287 static id<MTLSamplerState> samplerLinearClamp = nil;
288 static id<MTLSamplerState> samplerNearestRepeat = nil;
289 static id<MTLSamplerState> samplerLinearRepeat = nil;
290
291 void initSamplers(id<MTLDevice> device) {
292 // TODO: move this code into SamplerManager (need implement)
293
294 if (samplerNearestClamp != nil)
295 return;
296
297 MTLSamplerDescriptor *samplerDescriptor = [MTLSamplerDescriptor new];
298
299 samplerDescriptor.rAddressMode = MTLSamplerAddressModeClampToEdge;
300 samplerDescriptor.sAddressMode = MTLSamplerAddressModeClampToEdge;
301 samplerDescriptor.tAddressMode = MTLSamplerAddressModeClampToEdge;
302
303 samplerDescriptor.minFilter = MTLSamplerMinMagFilterNearest;
304 samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest;
305 samplerNearestClamp = [device newSamplerStateWithDescriptor:samplerDescriptor];
306
307 samplerDescriptor.minFilter = MTLSamplerMinMagFilterLinear;
308 samplerDescriptor.magFilter = MTLSamplerMinMagFilterLinear;
309 samplerLinearClamp = [device newSamplerStateWithDescriptor:samplerDescriptor];
310
311 samplerDescriptor.rAddressMode = MTLSamplerAddressModeRepeat;
312 samplerDescriptor.sAddressMode = MTLSamplerAddressModeRepeat;
313 samplerDescriptor.tAddressMode = MTLSamplerAddressModeRepeat;
314
315 samplerDescriptor.minFilter = MTLSamplerMinMagFilterNearest;
316 samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest;
317 samplerNearestRepeat = [device newSamplerStateWithDescriptor:samplerDescriptor];
318
319 samplerDescriptor.minFilter = MTLSamplerMinMagFilterLinear;
320 samplerDescriptor.magFilter = MTLSamplerMinMagFilterLinear;
321 samplerLinearRepeat = [device newSamplerStateWithDescriptor:samplerDescriptor];
322 }
323
324 static void setTxtUniforms(
325 id<MTLRenderCommandEncoder> encoder, int color, int mode, int interpolation, bool repeat, jfloat extraAlpha,
326 const SurfaceRasterFlags * srcFlags, const SurfaceRasterFlags * dstFlags
327 ) {
328 struct TxtFrameUniforms uf = {RGBA_TO_V4(color), mode, srcFlags->isOpaque, dstFlags->isOpaque, interpolation};
329 [encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
330
331 id<MTLSamplerState> sampler;
332 if (repeat) {
333 sampler = interpolation == INTERPOLATION_BILINEAR ? samplerLinearRepeat : samplerNearestRepeat;
334 } else {
335 sampler = interpolation == INTERPOLATION_BILINEAR ? samplerLinearClamp : samplerNearestClamp;
336 }
337 [encoder setFragmentSamplerState:sampler atIndex:0];
338 }
339
340 // TODO: need support hints for all shaders
341
342 // For the current paint mode:
343 // 1. Selects vertex+fragment shaders (and corresponding pipelineDesc) and set pipelineState
344 // 2. Set vertex and fragment buffers
345 - (void)setPipelineState:(id<MTLRenderCommandEncoder>)encoder
346 composite:(MTLComposite *)composite
347 isStencilUsed:(jboolean)isStencilUsed
348 isTexture:(jboolean)isTexture
349 interpolation:(int)interpolation
350 isAA:(jboolean)isAA
351 srcFlags:(const SurfaceRasterFlags *)srcFlags
352 dstFlags:(const SurfaceRasterFlags *)dstFlags
353 pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage
354 {
355 initTemplatePipelineDescriptors();
356
357 const bool stencil = isStencilUsed == JNI_TRUE;
358
359 id<MTLRenderPipelineState> pipelineState = nil;
360 if (isTexture) {
361
362 if (_paintState == sun_java2d_SunGraphics2D_PAINT_TEXTURE) {
363 pipelineState = [pipelineStateStorage getPipelineState:templateTexturePipelineDesc
364 vertexShaderId:@"vert_txt_tp"
365 fragmentShaderId:@"frag_txt_tp"
366 compositeRule:[composite getRule]
367 isAA:JNI_FALSE
368 srcFlags:srcFlags
369 dstFlags:dstFlags
370 stencilNeeded:stencil];
371 [encoder setVertexBytes:&_anchor length:sizeof(_anchor) atIndex:FrameUniformBuffer];
372 [encoder setFragmentTexture:_paintTexture atIndex: 1];
373
374 setTxtUniforms(encoder, 0, 0, interpolation, YES, [composite getExtraAlpha], srcFlags, dstFlags);
375 } else if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
376 pipelineState = [pipelineStateStorage getPipelineState:templateTexturePipelineDesc
377 vertexShaderId:@"vert_txt_grad"
378 fragmentShaderId:@"frag_txt_grad"
379 compositeRule:[composite getRule]
380 isAA:JNI_FALSE
381 srcFlags:srcFlags
382 dstFlags:dstFlags
383 stencilNeeded:stencil];
384 struct GradFrameUniforms uf = {
385 {_p0, _p1, _p3},
386 RGBA_TO_V4(_pixel1),
387 RGBA_TO_V4(_pixel2)};
388 [encoder setFragmentBytes: &uf length:sizeof(uf) atIndex:0];
389
390 } else {
391 if (isAA) {
392 pipelineState = [pipelineStateStorage
393 getPipelineState:templateAATexturePipelineDesc
394 vertexShaderId:@"vert_txt"
395 fragmentShaderId:@"aa_frag_txt"
396 compositeRule:[composite getRule]
397 isAA:JNI_FALSE
398 srcFlags:srcFlags
399 dstFlags:dstFlags
400 stencilNeeded:stencil];
401
402 } else {
403 pipelineState =
404 [pipelineStateStorage getPipelineState:templateTexturePipelineDesc
405 vertexShaderId:@"vert_txt"
406 fragmentShaderId:@"frag_txt"
407 compositeRule:[composite getRule]
408 composite:composite
409 isAA:JNI_FALSE
410 srcFlags:srcFlags
411 dstFlags:dstFlags
412 stencilNeeded:stencil];
413 }
414
415 setTxtUniforms(encoder, _color, _paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR ? 1 : 0, interpolation, NO, [composite getExtraAlpha], srcFlags, dstFlags);
416 }
417 } else {
418 if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
419 pipelineState = [pipelineStateStorage getPipelineState:templateRenderPipelineDesc
420 vertexShaderId:@"vert_col"
421 fragmentShaderId:@"frag_col"
422 compositeRule:[composite getRule]
423 isAA:isAA
424 srcFlags:srcFlags
425 dstFlags:dstFlags
426 stencilNeeded:stencil];
427
428 struct FrameUniforms uf = {RGBA_TO_V4(_color)};
429 [encoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
430 } else if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
431 pipelineState = [pipelineStateStorage getPipelineState:templateRenderPipelineDesc
432 vertexShaderId:@"vert_grad"
433 fragmentShaderId:@"frag_grad"
434 compositeRule:[composite getRule]
435 isAA:isAA
451 srcFlags:srcFlags
452 dstFlags:dstFlags
453 stencilNeeded:stencil];
454
455 [encoder setVertexBytes:&_anchor length:sizeof(_anchor) atIndex:FrameUniformBuffer];
456 [encoder setFragmentTexture:_paintTexture atIndex: 0];
457 }
458 }
459
460 [encoder setRenderPipelineState:pipelineState];
461 }
462
463
464 // For the current paint mode: and for XOR composite - a separate method is added as fragment shader differ in some cases
465 // 1. Selects vertex+fragment shaders (and corresponding pipelineDesc) and set pipelineState
466 // 2. Set vertex and fragment buffers
467 - (void)setXorModePipelineState:(id<MTLRenderCommandEncoder>)encoder
468 composite:(MTLComposite *)composite
469 isStencilUsed:(jboolean)isStencilUsed
470 isTexture:(jboolean)isTexture
471 interpolation:(int)interpolation
472 srcFlags:(const SurfaceRasterFlags *)srcFlags
473 dstFlags:(const SurfaceRasterFlags *)dstFlags
474 pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage {
475 initTemplatePipelineDescriptors();
476
477 const bool stencil = isStencilUsed == JNI_TRUE;
478 jint xorColor = (jint) [composite getXorColor];
479
480 id<MTLRenderPipelineState> pipelineState = nil;
481 if (isTexture) {
482 pipelineState = [pipelineStateStorage getXorModePipelineState:templateTexturePipelineDesc
483 vertexShaderId:@"vert_txt"
484 fragmentShaderId:@"frag_txt"
485 srcFlags:srcFlags
486 dstFlags:dstFlags
487 stencilNeeded:stencil];
488 const int col = _paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR ? _color ^ xorColor : 0 ^ xorColor;
489 setTxtUniforms(encoder, col, _paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR ? 1 : 0, interpolation, NO, [composite getExtraAlpha], srcFlags, dstFlags);
490 [encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex: 0];
491 } else {
492 if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
493
494 pipelineState = [pipelineStateStorage getXorModePipelineState:templateRenderPipelineDesc
495 vertexShaderId:@"vert_col"
496 fragmentShaderId:@"frag_col"
497 srcFlags:srcFlags
498 dstFlags:dstFlags
499 stencilNeeded:stencil];
500
501 // Calculate _color ^ xorColor for RGB components
502 // This color gets XORed with destination framebuffer pixel color
503 struct FrameUniforms uf = {RGBA_TO_V4(_color ^ xorColor)};
504 [encoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
505
506 } else if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
507
508 pipelineState = [pipelineStateStorage getXorModePipelineState:templateRenderPipelineDesc
509 vertexShaderId:@"vert_grad"
|
266 filter:(jboolean)filter
267 xp0:(jdouble)xp0
268 xp1:(jdouble)xp1
269 xp3:(jdouble)xp3
270 yp0:(jdouble)yp0
271 yp1:(jdouble)yp1
272 yp3:(jdouble)yp3
273 {
274 _paintState = sun_java2d_SunGraphics2D_PAINT_TEXTURE;
275 _paintTexture = textureID;
276
277 _anchor.xParams[0] = xp0;
278 _anchor.xParams[1] = xp1;
279 _anchor.xParams[2] = xp3;
280
281 _anchor.yParams[0] = yp0;
282 _anchor.yParams[1] = yp1;
283 _anchor.yParams[2] = yp3;
284 }
285
286 // For the current paint mode:
287 // 1. Selects vertex+fragment shaders (and corresponding pipelineDesc) and set pipelineState
288 // 2. Set vertex and fragment buffers
289 - (void)setPipelineState:(id<MTLRenderCommandEncoder>)encoder
290 composite:(MTLComposite *)composite
291 isStencilUsed:(jboolean)isStencilUsed
292 isTexture:(jboolean)isTexture
293 isAA:(jboolean)isAA
294 srcFlags:(const SurfaceRasterFlags *)srcFlags
295 dstFlags:(const SurfaceRasterFlags *)dstFlags
296 pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage
297 {
298 initTemplatePipelineDescriptors();
299
300 const bool stencil = isStencilUsed == JNI_TRUE;
301
302 id<MTLRenderPipelineState> pipelineState = nil;
303 if (isTexture) {
304
305 if (_paintState == sun_java2d_SunGraphics2D_PAINT_TEXTURE) {
306 pipelineState = [pipelineStateStorage getPipelineState:templateTexturePipelineDesc
307 vertexShaderId:@"vert_txt_tp"
308 fragmentShaderId:@"frag_txt_tp"
309 compositeRule:[composite getRule]
310 isAA:JNI_FALSE
311 srcFlags:srcFlags
312 dstFlags:dstFlags
313 stencilNeeded:stencil];
314 [encoder setVertexBytes:&_anchor length:sizeof(_anchor) atIndex:FrameUniformBuffer];
315 [encoder setFragmentTexture:_paintTexture atIndex: 1];
316
317 struct TxtFrameUniforms uf = {RGBA_TO_V4(0), 0, srcFlags->isOpaque,
318 dstFlags->isOpaque, [composite getExtraAlpha]};
319 [encoder setFragmentBytes:&uf length:sizeof(uf)
320 atIndex:FrameUniformBuffer];
321
322 } else if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
323 pipelineState = [pipelineStateStorage getPipelineState:templateTexturePipelineDesc
324 vertexShaderId:@"vert_txt_grad"
325 fragmentShaderId:@"frag_txt_grad"
326 compositeRule:[composite getRule]
327 isAA:JNI_FALSE
328 srcFlags:srcFlags
329 dstFlags:dstFlags
330 stencilNeeded:stencil];
331 struct GradFrameUniforms uf = {
332 {_p0, _p1, _p3},
333 RGBA_TO_V4(_pixel1),
334 RGBA_TO_V4(_pixel2)};
335 [encoder setFragmentBytes: &uf length:sizeof(uf) atIndex:0];
336
337 } else {
338 if (isAA) {
339 pipelineState = [pipelineStateStorage
340 getPipelineState:templateAATexturePipelineDesc
341 vertexShaderId:@"vert_txt"
342 fragmentShaderId:@"aa_frag_txt"
343 compositeRule:[composite getRule]
344 isAA:JNI_FALSE
345 srcFlags:srcFlags
346 dstFlags:dstFlags
347 stencilNeeded:stencil];
348
349 } else {
350 pipelineState =
351 [pipelineStateStorage getPipelineState:templateTexturePipelineDesc
352 vertexShaderId:@"vert_txt"
353 fragmentShaderId:@"frag_txt"
354 compositeRule:[composite getRule]
355 composite:composite
356 isAA:JNI_FALSE
357 srcFlags:srcFlags
358 dstFlags:dstFlags
359 stencilNeeded:stencil];
360 }
361
362 if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
363 struct TxtFrameUniforms uf = {RGBA_TO_V4(_color), 1,
364 srcFlags->isOpaque, dstFlags->isOpaque, [composite getExtraAlpha]};
365 [encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
366 } else {
367 struct TxtFrameUniforms uf = {RGBA_TO_V4(0), 0,
368 srcFlags->isOpaque, dstFlags->isOpaque, [composite getExtraAlpha]};
369 [encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
370 }
371 }
372 } else {
373 if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
374 pipelineState = [pipelineStateStorage getPipelineState:templateRenderPipelineDesc
375 vertexShaderId:@"vert_col"
376 fragmentShaderId:@"frag_col"
377 compositeRule:[composite getRule]
378 isAA:isAA
379 srcFlags:srcFlags
380 dstFlags:dstFlags
381 stencilNeeded:stencil];
382
383 struct FrameUniforms uf = {RGBA_TO_V4(_color)};
384 [encoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
385 } else if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
386 pipelineState = [pipelineStateStorage getPipelineState:templateRenderPipelineDesc
387 vertexShaderId:@"vert_grad"
388 fragmentShaderId:@"frag_grad"
389 compositeRule:[composite getRule]
390 isAA:isAA
406 srcFlags:srcFlags
407 dstFlags:dstFlags
408 stencilNeeded:stencil];
409
410 [encoder setVertexBytes:&_anchor length:sizeof(_anchor) atIndex:FrameUniformBuffer];
411 [encoder setFragmentTexture:_paintTexture atIndex: 0];
412 }
413 }
414
415 [encoder setRenderPipelineState:pipelineState];
416 }
417
418
419 // For the current paint mode: and for XOR composite - a separate method is added as fragment shader differ in some cases
420 // 1. Selects vertex+fragment shaders (and corresponding pipelineDesc) and set pipelineState
421 // 2. Set vertex and fragment buffers
422 - (void)setXorModePipelineState:(id<MTLRenderCommandEncoder>)encoder
423 composite:(MTLComposite *)composite
424 isStencilUsed:(jboolean)isStencilUsed
425 isTexture:(jboolean)isTexture
426 srcFlags:(const SurfaceRasterFlags *)srcFlags
427 dstFlags:(const SurfaceRasterFlags *)dstFlags
428 pipelineStateStorage:(MTLPipelineStatesStorage *)pipelineStateStorage {
429 initTemplatePipelineDescriptors();
430
431 const bool stencil = isStencilUsed == JNI_TRUE;
432 jint xorColor = (jint) [composite getXorColor];
433
434 id<MTLRenderPipelineState> pipelineState = nil;
435 if (isTexture) {
436 pipelineState = [pipelineStateStorage getXorModePipelineState:templateTexturePipelineDesc
437 vertexShaderId:@"vert_txt"
438 fragmentShaderId:@"frag_txt"
439 srcFlags:srcFlags
440 dstFlags:dstFlags
441 stencilNeeded:stencil];
442
443 if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
444 struct TxtFrameUniforms uf = {RGBA_TO_V4(_color ^ xorColor), 1,
445 srcFlags->isOpaque, dstFlags->isOpaque, [composite getExtraAlpha]};
446 [encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
447 } else {
448 struct TxtFrameUniforms uf = {RGBA_TO_V4(0 ^ xorColor), 0,
449 srcFlags->isOpaque, dstFlags->isOpaque, [composite getExtraAlpha]};
450 [encoder setFragmentBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
451 }
452 [encoder setFragmentBytes:&xorColor length:sizeof(xorColor) atIndex: 0];
453 } else {
454 if (_paintState == sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
455
456 pipelineState = [pipelineStateStorage getXorModePipelineState:templateRenderPipelineDesc
457 vertexShaderId:@"vert_col"
458 fragmentShaderId:@"frag_col"
459 srcFlags:srcFlags
460 dstFlags:dstFlags
461 stencilNeeded:stencil];
462
463 // Calculate _color ^ xorColor for RGB components
464 // This color gets XORed with destination framebuffer pixel color
465 struct FrameUniforms uf = {RGBA_TO_V4(_color ^ xorColor)};
466 [encoder setVertexBytes:&uf length:sizeof(uf) atIndex:FrameUniformBuffer];
467
468 } else if (_paintState == sun_java2d_SunGraphics2D_PAINT_GRADIENT) {
469
470 pipelineState = [pipelineStateStorage getXorModePipelineState:templateRenderPipelineDesc
471 vertexShaderId:@"vert_grad"
|