[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Public WebGL] Some WebGL draft feedback



On Wed, Jan 6, 2010 at 11:23 AM, Chris Marrin <cmarrin@apple.com> wrote:
>
> On Jan 6, 2010, at 4:25 AM, Philip Taylor wrote:
>
>> On Wed, Jan 6, 2010 at 3:10 AM, Mark Callow <callow_mark@hicorp.co.jp> wrote:
>>> I think we should not support simultaneous rendering by different APIs at
>>> the first release. We can leave the door open so if there is great demand
>>> for the feature it can be added in a future release. A restriction now that
>>> canvas.getContext() destroys any existing context, thus preventing
>>> simultaneous rendering, can easily be relaxed in the future without breaking
>>> any applications.
>>
>> Consider a situation where browsers don't support simultaneous
>> rendering, and I write an application that needs to mix 2D and 3D, so
>> I do something a bit slow and ugly with multiple canvases or some
>> intermediate textures etc. Then one browser releases a new version
>> that does support simultaneous rendering, so my application could be
>> written more cleanly and efficiently. How do I use the new method in
>> browsers that support simultaneous rendering, and fall back to the old
>> method in the older browsers? If getContext silently destroys an
>> existing context in old browsers, it seems very difficult for me to
>> tell whether it's safe to use contexts simultaneously or not.
>
> Right, this is the conversation we need to have here and with the HTML5 WG. What is the semantics of getContext()?
>
>>
>> So the feature should be designed in such a way that it's easy to test
>> for the feature in future browsers. (And it should be easy to test for
>> the similar feature between any pair or set of contexts that are
>> defined in the future, not just 2D+WebGL). Maybe it should just throw
>> an exception if you try to use incompatible contexts - if you've
>> already called getContext('2d') then the getContext('webgl') call will
>> throw, and vice versa, if the browser doesn't support simultaneous
>> rendering. That makes it easy to detect in script. That also prevents
>> authors getting confused by drawing to one context and not seeing the
>> output because the other context is being drawn instead, with no error
>> message to indicate the problem. It also makes extension contexts like
>> opera-2dgame fit easily within the model: it's compatible with the 2d
>> context, but incompatible with the 3d context, so you can't mix them
>> incorrectly. And it prevents all the questions about what happens if
>> you try to use both 2d and webgl contexts (in a browser that doesn't
>> support simultaneous rendering) and then use getImageData and
>> glReadPixels and drawImage(canvas) and glTexImage2D(canvas) and
>> toDataURL - now the canvas will only ever have a single bitmap (though
>> it might be 'owned' by either the 2d or webgl contexts), so there's no
>> longer a question of which bitmap the methods access.
>
> Your proposal, throwing when you try to change APIs is pretty good, but I'm not a big fan of using exceptions as a way of determining features. Perhaps a better approach would be to return null instead of throwing.
>
> I recently proposed that an alternative to simultaneous rendering is to preserve the color buffer data when switching APIs. Perhaps all these problems could be solved if we just added a locking mechanism to Canvas. It would work like this:
>
> If simultaneous rendering is not supported then attempting to do a getContext() for an API after a different API has been gotten for that Canvas returns null, and the originally gotten context is still valid. This provides no way of switching the rendering API on a given Canvas. I think that's fine for a first implementation. You can always destroy and recreate the Canvas element if need be.
>
> If simultaneous rendering is supported then attempting to do a getContext() for an API after a context for a different API has been gotten returns the context for the new API, enables it for rendering to the Canvas and disables the previously enabled context. Attempting to make any API calls on a disabled context throws an exception.When the new context is gotten, the color buffer from the previous context remains valid, but any other buffers (such as depth and stencil buffers) are removed. When the the context with these buffers is again gotten, the extra buffers are initialized as though this were the first call to getContext() for this API. After the first getContext() call to get a given context, all subsequent calls to get that same context are guaranteed to return the same object.
>
> That description leaves a lot to be desired, so here's an example which will hopefully clear things up. I'll use Gregg's example:
>
>        var ctx2d = canvas.getContext("2d");                    // ctx2d is now enabled, Canvas is initialized to transparent black
>        ctx2d.drawImage(someFlowerImage, 0, 0);                 // Canvas now contains flower image
>
>        // Blur out the flowers
>        var ctxFilter = canvas.getContext("filters");           // ctx2d is disabled, ctxFilter is enabled, Canvas has flower image
>        if (!ctxFilter) {
>                // Oh well, simultaneous rendering not supported
>                return;
>        }
>        ctxFilter.radialBlur(50.5);                                             // flower image is blurred
>
>        // Draw some text on a curve
>        var ctxWordArt = canvas.getContext("word-art"); // ctxFilter is disabled, ctxWordArt is enabled, Canvas has a blurred flower image
>        ctxWordArt.setColor(0, 0, 0);
>        ctxWordArt.defineCurvePath([100, 100, 150, 50, 200, 300, 400]);
>        ctxWordArt.drawTextAlongCurve("Hello world");   // Canvas now has "Hello World" on top of the blurred flower
>
>        // Blur out the text we just drew
>        canvas.getContext("filters");                                   // ctxWordArt is disabled, ctxFilter is enabled
>        ctxFilter.zoomBlur(0.5);                                                // Flower is more blurry, text is also blurry
>
>        // Draw the text again clearly on top of the blurred text.
>        canvas.getContext("word-art");                          // ctxFilter is disabled, ctxWordArt is enabled
>        ctxWordArt.setColor(255, 0, 0);
>        ctxWordArt.drawTextAlongCurve("Hello world");   // Canvas now has really blurry flower, blurred text and sharp text over it
>
> The only difference between this and Gregg's example is that I check to see if simultaneous rendering is supported and I added a couple of getContext() calls to switch the enabled context. You'll notice that on the subsequent getContext() calls, I didn't bother assigning their value because we would guarantee that it would return the same object reference.
>
> This is nice in a few ways:
>
> 1) No API change, just a change in the semantics
> 2) getContext() gives us a nice synchronization point
> 3) Support is optional, this won't hold up current implementations
> 4) The semantics about what the canvas buffer contains after the switch is clear
>
>>
>> (The concept of incompatible contexts should be defined in HTML5,
>> since it's not specific to WebGL - the editor has said he'd be happy
>> to change what HTML5 currently defines, if someone tells him what it
>> should say instead.)
>
> That's a very useful bit of information. Do you think the HTML5 Editor (and other interested parties) would want to discuss the issues here?

This topic was discussed on today's conference call. Here's a summary
of the points:

1) There was general agreement that supporting multiple simultaneous
contexts on the canvas is useful to the developer.

2) There was agreement that interoperability between various contexts
can be achieved in the worst case by reading back the framebuffer into
system memory, and that optimizations can be done to achieve higher
performance without changing the public APIs or forcing the developer
to re-fetch contexts from the canvas to indicate which one is current.
Exactly what information would be shared among various contexts would
need to be more precisely specified. Today, only the color planes
would be shared between the 2D and WebGL contexts, for example. There
are open questions about the state of things like the stencil and
depth buffers if first WebGL content is drawn and then 2D content is
drawn, in particular if future 2D context implementations are fully
hardware accelerated.

3) There was a desire to not require support for simultaneous contexts
in the first release of the WebGL specification. (Multiple context
support really needs to be defined in the HTML5 Canvas specification,
anyway, and not the WebGL specification.) Consequently, we need to
think about how to make it easy for the developer to query whether
multiple contexts are supported, and not make API design decisions
that would prevent introduction of multiple context support in the
future.

Kenneth Waters pointed out that in EGL, requests to render using
multiple APIs (like OpenGL and OpenVG) need to be made at context and
surface creation time. Therefore, to make sure we don't inhibit
hardware accelerated implementations of multiple contexts on the
canvas, we would need to make sure that all of the requests for
multiple contexts are made early. This would also make it easier for
the developer to write fallback paths in the case that multiple
contexts aren't supported.

One suggestion that was discussed is to return null from getContext()
if it's called more than once and if the implementation doesn't
support multiple contexts. This is most compatible with the current
HTML5 Canvas API; see
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-canvas-getcontext
. If the implementation does support multiple contexts, the developer
would be required to fetch all of the contexts they intend to render
with up front, before doing any rendering with any of them. This would
allow WebGL implementations to allocate the rendering surface and
context lazily, and to add in any context creation flags necessary to
support hardware accelerated rendering from multiple APIs.

Here's an example of this in use:

    // Fetch all contexts; this is done once at application startup
    var ctx2d = canvas.getContext("2d");
    var gl = canvas.getContext("webgl");
    var filters = canvas.getContext("filters");

    // Use of contexts in rendering loop
    gl.drawElements(...);  // Draw 3D model
    filters.radialBlur(0.5);  // Bloom filter
    ctx2d.fillText("Score: " + score, 10, 10); // Overly current score
on 3D rendering

Here's a negative example:

    var gl = canvas.getContext("webgl");
    gl.drawElements(...);  // Rendering has been done with this context
    var ctx2d = canvas.getContext("2d");  // Returns null because all
contexts weren't fetched before rendering was done

If we can agree that this is a reasonable model, I'll update Section
2.1 to take it into account.

-Ken

-----------------------------------------------------------
You are currently subscribe to public_webgl@khronos.org.
To unsubscribe, send an email to majordomo@khronos.org with
the following command in the body of your email: