SKShader compile error with preprocessor directive (so can't use programmable blending)

Anybody have a workaround for using the "#extension" preprocessor directive with an SKShader? In addition to SKShader(fileNamed: <nameOfFile>), I've tried using "#extension" in SKShader(source: <String>) and SKShader(source: <String>, uniforms: <[SKUniform]>) and they don't compile either. This happens even with PrefersOpenGL=YES (and also with PrefersOpenGL=NO).


I filed an Apple Bug Reporter bug and an official Apple Technical Support Incident request. Apple tech support summarily told me that they would not look at this problem because it pertained to the beta versions of iOS and Xcode. I will try (likely) to reproduce them on non-beta versions of iOS and Xcode. This is an important problem with SKShader because it doesn't allow the programmable blending extension to be compiled.


Here are the details of the problem:


PLATFORM AND VERSION

iOS 10.2 and Xcode Version 8.2 beta (8C30a) on an iPhone 6s plus


DESCRIPTION OF PROBLEM

I described this in Apple Bug Reporter #29429243 and uploaded a project example that reproduces the problem.


Summary:

Trying to compile a shader file with "#extension EXT_shader_framebuffer_fetch : require" as the source for an SKShader fails. This happens even with PrefersOpenGL=YES.


Here is info from the Open GL ES Analyzer:


Shader #2 - Your application unsuccessfully attempted to compile a shader. See the info log below:


Info Log:

ERROR: 0:1: '' : syntax error: preprocessor command must not be preceded by any other statement in that line



0 0x10029bf5c

1 Jet xglCompileShader(unsigned int*, unsigned int, char const*, std::__1::basic_string, std::__1::allocator >**)

2 Jet jet_context_OpenGL::create_function_from_source(char const*, char const*, jet_function_type, std::__1::basic_string, std::__1::allocator >**)

3 SpriteKit __50-[SKShader _makeBackingProgramWithImplementation:]_block_invoke

4 SpriteKit ___Z27SKCPerformResourceOperationU13block_pointerFvNSt3__110shared_ptrI11jet_contextEEE_block_invoke

5 libdispatch.dylib _dispatch_client_callout

6 libdispatch.dylib _dispatch_barrier_sync_f_invoke

7 SpriteKit SKCPerformResourceOperation(void (std::__1::shared_ptr) block_pointer)

8 SpriteKit -[SKShader _makeBackingProgramWithImplementation:]

9 SpriteKit -[SKShader _backingProgram]

10 SpriteKit SKCRenderer::flushCurrentBatch()

11 SpriteKit SKCRenderer::expandRenderGroup(std::__1::shared_ptr const&, std::__1::shared_ptr const&)

12 SpriteKit SKCRenderer::expandRenderPass(std::__1::shared_ptr const&, std::__1::shared_ptr const&)

13 SpriteKit SKCRenderer::render(SKCNode*, float vector[4], std::__1::shared_ptr const&, unsigned int vector[4], matrix_float4x4, bool, NSDictionary*, SKCStats*, SKCStats*, double)

14 SpriteKit __59-[SKView _renderSynchronouslyForTime:preRender:postRender:]_block_invoke

15 SpriteKit -[SKView _renderSynchronouslyForTime:preRender:postRender:]

16 SpriteKit -[SKView layoutSubviews]

17 UIKit -[UIView(CALayerDelegate) layoutSublayersOfLayer:]

18 QuartzCore -[CALayer layoutSublayers]

19 QuartzCore CA::Layer::layout_if_needed(CA::Transaction*)

20 QuartzCore CA::Layer::layout_and_display_if_needed(CA::Transaction*)

21 QuartzCore CA::Context::commit_transaction(CA::Transaction*)

22 QuartzCore CA::Transaction::commit()

23 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*)

24 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__

25 CoreFoundation __CFRunLoopDoObservers

26 CoreFoundation CFRunLoopRunSpecific

27 UIKit -[UIApplication _run]

28 UIKit UIApplicationMain

29 BlendShader 0x10008d43c

30 libdyld.dylib start




STEPS TO REPRODUCE

Steps to Reproduce:

Zip file attached in #29429243 that reproduces problem.

Here are the steps:


1. Create a SpriteKit app

2. Add a createShader() function to the didMove()

3. In createShader(), create an SKShader with a source file that includes the #extension directive, namely:


"#extension EXT_shader_framebuffer_fetch : require


void main() {

gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);

}"


4. Create an SKSpriteNode and set its shader property to the SKShader.


5. Add the SKSpriteNode to the scene.


Expected Results:

Expect the shader to compile


Actual Results:

Encounter following shader compile error:


ERROR: 0:1: '' : syntax error: preprocessor command must not be preceded by any other statement in that line



Note The Metal version equivalent of programmable blending from 4.7 in https://developer.apple.com/metal/metal-shading-language-specification.pdf does not compile either (with PrefersOpenGL=NO or PrefersOpenGL=YES):


#include

using namespace metal;

fragment half4

paint_grayscale(half4 dst_color [[color(0)]])

{


// RGB to grayscale

half lum = dot(dst_color.rgb,

half3(0.30h, 0.59h, 0.11h));

return half4(lum, lum, lum, 1.0h);

}


I get a "SKShader 'shader_blend.fsh' failed to compile:"



Please let me know if you have a workaround!


Thank you!