SkSL Shader - eglSwapBuffers() very slow

221 views
Skip to first unread message

pearleye

unread,
Jun 8, 2023, 6:48:37 PM6/8/23
to skia-discuss
Hi
I'm working on implementing the below example in an Android platform and I see that it nearly takes 6 seconds to complete eglSwapBuffers() call!


Below is the code snippet, What am I doing wrong?

SkColorType colorType = kN32_SkColorType;

GrGLFramebufferInfo fbInfo;
fbInfo.fFBOID = 0;
fbInfo.fFormat = GR_GL_RGBA8;

GrBackendRenderTarget backendRT(mWidth, mHeight, 0, STENCIL_BUFFER_SIZE, fbInfo);

SkSurfaceProps props(0, kUnknown_SkPixelGeometry);

sk_sp<SkSurface> surface = SkSurface::MakeFromBackendRenderTarget(
mGrContext.get(),
backendRT,
kBottomLeft_GrSurfaceOrigin,
colorType,
nullptr,
&props));

mCanvas = surface->getCanvas();

int frames = 100;
float frame;
static int frameCounter;
double duration = SkTime::GetMSecs();

if (++frameCounter > frames) { frameCounter = 1; }

frame = (float)((float)frameCounter /(float) frames);
SkV3 viewportResolution = SkV3{(float)mWidth, (float)mHeight, 1.0f};

const float playbackTime = duration != 0.0 ? frame * duration : 0.0;

constexpr char prog1[] = R"(
uniform float3 iResolution; // Viewport resolution (pixels)
uniform float iTime; // Shader playback time (s)
uniform float3 iImageResolution; // iImage1 resolution (pixels)
in fragmentProcessor iImage1; // An input image.

void main(float2 FC, inout half4 o) {
o = half4(0);
float2 p = float2(0), c=p, u=FC.xy*2.-iResolution.xy;
float a;
for (float i=0; i<4e2; i++) {
a = i/2e2-1.;
p = cos(i*2.4+iTime+float2(0,11))*sqrt(1.-a*a);
c = u/iResolution.y+float2(p.x,a)/(p.y+2.);
o += half4((cos(i+float4(0,2,4,0))+1.)/dot(c,c)*(1.-p.y)/3e4);
}
}
)";
auto [effect1, err1] = SkRuntimeEffect::Make(SkString(prog1));

struct Uniforms
{
SkV3 iResolution;
float iTime;
SkV3 iImageResolution;
} uniform;

uniform.iResolution = viewportResolution;
uniform.iTime = playbackTime;
uniform.iImageResolution = SkV3{static_cast<float>(image->width()),
static_cast<float>(image->height()), 1.0f};
sk_sp<SkData> data = SkData::MakeWithCopy(&uniform, sizeof(uniform));

sk_sp<SkShader> children[] = {image->makeShader()};

sk_sp<SkShader> shader1 = effect1->makeShader(data, children, 1, nullptr, true);

mCanvas->clear(SK_ColorBLACK);

SkPaint p;
p.setShader(shader1);
mCanvas->drawPaint(p);
mCanvas->flush();
eglSwapBuffers(mEglDisplay, mEglSurface);

John Stiles

unread,
Jun 8, 2023, 6:54:15 PM6/8/23
to skia-discuss
What do you mean by "Android platform"? Is this on a real phone, or an emulator…? 

pearleye

unread,
Jun 9, 2023, 9:56:43 AM6/9/23
to skia-discuss
It's on the Set-top box (Android TV AOSP 11) where the version of Skia is M82.

John Stiles

unread,
Jun 9, 2023, 9:59:18 AM6/9/23
to skia-discuss
What type of set-top box in particular? What GPU does it have? What resolution is the surface?
This is not a lightweight shader. If you're running it at 4K with a weak GPU, it may just be limited by the hardware.
On the other hand, it might be a totally different issue, but it's hard to diagnose "this shader runs slowly" without any information about the hardware you're using.


John Stiles

unread,
Jun 9, 2023, 10:09:23 AM6/9/23
to skia-discuss
Also, one experiment we could easily try—swap in a very simple shader and see how the performance changes. Here's an example shader that is very simple but still manages to have an interesting look:
https://shaders.skia.org/?id=c93763d5a014bbfadb9155035b2748161b52a431a7fedb03d0175bd67d8fe363

pearleye

unread,
Jun 9, 2023, 11:12:50 AM6/9/23
to skia-discuss
Below are the hardware specs of the set-top box I'm using now,
    Chipset --> Amlogic ARMv7-A,  ClockSpeed - (100MHZ - 1800MHZ), Cores - 4
    Ram --> 1960 MB
    Resolution --> Full HD (1920*1080), Refresh rate - 60Hz

Meantime I'm working on trying out the example shader which you shared and the output which I see is different!

I had to change the types like vec2/vec4 to float2/float4 and return value of main to void, since the SKIA version which I have is 'Milestone 82'.

Did I change it right?

constexpr char prog1[] = R"(
uniform float3 iResolution;
uniform float iTime;
uniform float3 iImageResolution;
in fragmentProcessor iImage1;
void main(float2 FC, inout half4 color) {
float2 position = - 1.0 + 2.0 * FC.xy / iImageResolution.xy;
float red = abs( sin( position.x * position.y + iTime / 5.0 ) );
float green = abs( sin( position.x * position.y + iTime / 4.0 ) );
float blue = abs( sin( position.x * position.y + iTime / 3.0 ) );
color = half4(float4( red, green, blue, 1.0 ));
}
)";

John Stiles

unread,
Jun 9, 2023, 11:23:52 AM6/9/23
to skia-d...@googlegroups.com
What do you mean when you say "the output which I see is different"? 

The only thing that jumps out at me is that "iImage1" is unused, and you're using "iImageResolution" where I would have expected you to use "iResolution". iResolution would presumably be the size of the surface, and iImageResolution would be the size of the (never used) image. Assuming the image is smaller than the surface, this mixup would give an image with a lot of arcs/curves in it, like this:


Is that what you see?
Also, how is the performance? If it's good, then I'd assume that the original issue was that the GPU was overwhelmed by a too-complex shader.


--
You received this message because you are subscribed to a topic in the Google Groups "skia-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/skia-discuss/Ao455K_NE8g/unsubscribe.
To unsubscribe from this group and all its topics, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/ef7acd9e-a9ff-40c2-919c-8aaf148f78ccn%40googlegroups.com.

pearleye

unread,
Jun 9, 2023, 1:35:32 PM6/9/23
to skia-discuss
You were absolutely right, I was getting the same arcs/curves as you shared! I had made the change to use iResolution and now it's almost similar to the actual output. But then I still have to feed the 'iTime' argument with a value increasing in chronological manner at least for a while.

And yes the performance is better!

As of now I'm calculating iTime as below,
    int frames = 100;
    float frame;
    static int frameCounter;
    double duration = SkTime::GetMSecs();

    if (++frameCounter > frames) { frameCounter = 1; }

    frame = (float)((float)frameCounter /(float) frames);

    iTime = frame * duration;

John Stiles

unread,
Jun 9, 2023, 1:43:07 PM6/9/23
to skia-discuss
I think this ought to be enough to get a valid iTime:

- When the animation starts:  
   double baseITime = SkTime::GetSecs();  // <-- save this value somewhere
- On every frame:
   double currentITime = SkTime::GetSecs() - baseITime;

Other than that, the only other advice I could offer would be to make sure you only call SkRuntimeEffect::Make once, not every frame. Your code snippet didn't include a main loop so I couldn't tell if you are doing this or not. But it's better to save the effect and reuse it, rather than making a new one every frame. (I don't remember if the API tries to cache the result if you call Make over and over again, but either way, even checking in the cache does take some time.)

pearleye

unread,
Jun 10, 2023, 9:56:22 AM6/10/23
to skia-discuss
Thanks a lot, I now get a similar output when iTime is calculated as you mentioned!

And yeah I've been doing 'SkRuntimeEffect::Make' in every frame which i'll move it elsewhere to do it only once.

1) With this shader example I get the max 60 FPS and I would like to find some other shader examples which stresses my GPU a bit which inturn brings down the FPS to benchmark across different vendors!
     Do you have any more shader examples which is not much intensive?

2) Could you explain in short like in which scenario I should be creating a surface from MakeFromBackendTexture instead of MakeFromBackendRenderTarget?

3) And is there any documentation I can find which explains all the SkSL types like float,vec,half4 etc? This is becuase I use skia version 'M82' and the examples from https://shaders.skia.org/ are not directly compatible with 'M82'.
     For eg, after quite a strugle I found the equivalent of 'uniform shader' is 'in fragmentProcessor'!

4) Is 'float2x2' the exact equivalent for 'mat2' in 'M82' version?

John Stiles

unread,
Jun 12, 2023, 9:45:02 AM6/12/23
to skia-d...@googlegroups.com
<<     Do you have any more shader examples which is not much intensive? >>


<< 2) Could you explain in short like in which scenario I should be creating a surface from MakeFromBackendTexture instead of MakeFromBackendRenderTarget? >>


<< 3) And is there any documentation I can find which explains all the SkSL types like float,vec,half4 etc? This is becuase I use skia version 'M82' and the examples from https://shaders.skia.org/ are not directly compatible with 'M82'. >> 

In M82, Runtime Effects were still in an experimental/work-in-progress state. It wasn't documented because it wasn't finished yet :) If you are serious about using Runtime Effects, you should strongly consider upgrading your Skia version. M82 was created over three years ago and there have been many, many improvements to Runtime Effects since then.

Off the top of my head, here's the primitive types:

The `float2`, `float3`, `float4` types correspond to GLSL `highp vec2`, `highp vec3`, `highp vec4`.
The `half2`/3/4 types correspond to GLSL `mediump vec2`/3/4.
The `float2x2`/3x3/4x4 types correspond to GLSL `highp mat2`/3/4.
The `half2x2`/3x3/4x4 types correspond to GLSL `medium mat2`/3/4.
The `bool2`/3/4 types correspond to GLSL `bvec2`/3/4.
The `int2`/3/4 types correspond to GLSL `ivec2`/3/4.

In today's Skia, you can just use the GLSL names directly and they work fine.
(Also, we've completely redone child shaders since M82 so the `in fragmentProcessor child;` syntax is obsolete—it's `uniform shader child;` now.)



Reply all
Reply to author
Forward
0 new messages