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

Re: [Public WebGL] getContext multiple context language



On Tue, Feb 2, 2010 at 2:55 PM, Vladimir Vukicevic <vladimir@mozilla.com> wrote:
> On 2/2/2010 2:31 PM, Kenneth Russell wrote:
>>
>> On Wed, Jan 27, 2010 at 3:22 PM, Vladimir Vukicevic
>> <vladimir@mozilla.com>  wrote:
>>
>>>
>>> Ok, here's the compromise language... on subsequent calls to getContext()
>>> for the same context, attrs must be either unspecified (in which case you
>>> get what's there), or if given, must be compatible with what's already
>>> active (or you get a hard error).
>>>
>>>     - Vlad
>>>
>>> object getContext(in DOMString contextId, in optional any attributes)
>>>
>>> A canvas may be rendered to using one or more contexts, each named by a
>>> string context ID.  For each canvas, there is a set of zero or more
>>> active
>>> contexts.  The getContext() method is used to obtain a particular
>>> rendering
>>> context for the canvas.
>>>
>>> 'contextId' must be a string naming a canvas rendering context to be
>>> returned.  For example, this specification defines the '2d' context,
>>> which,
>>> if requested, will return either a reference to an object implementing
>>> CanvasRenderingContext2D or null, if a 2D context cannot be created at
>>> this
>>> time.  Other specifications may define their own contexts, which would
>>> return different objects.
>>>
>>> If getContext() is called with a context ID that the implementation does
>>> not
>>> support, it must return null.
>>>
>>> For supported context IDs, the getContext() method behaves differently
>>> depending on whether the requested context ID is already an active
>>> context
>>> for the canvas.
>>>
>>> If there are no active contexts for the canvas, the implementation should
>>> attempt to create the specified context for the canvas.
>>>
>>> If there are one or more active contexts and a context ID that is not
>>> currently active is requested, it is up to the implementation to
>>> determine
>>> whether the requested context can be used simultaneously with all
>>> currently
>>> active canvas contexts.  If simultaneous rendering with the requested
>>> context is not possible, getContext() must return null.  Otherwise the
>>> implementation should attempt to create the specified context for the
>>> canvas.
>>>
>>> If a new context is to be created, the optional 'attributes' parameter
>>> must
>>> be either unspecified or an object specific to the context being
>>> requested.
>>> An unspecified value indicates a default set of attributes, as defined by
>>> the context. Unknown attributes should be ignored by the context.
>>>
>>> If a new context is successfully created, a reference to an object
>>> implementing the context API is returned and the new context is added to
>>> the
>>> list of active contexts for the canvas.
>>>
>>> If a context ID that is already an active context for the canvas is
>>> requested, then if the optional 'attributes' parameter is unspecified, a
>>> reference to the existing context object must be returned.  If the
>>> 'attributes' parameter is specified, the context must determine whether
>>> the
>>> given set of attributes is compatible with the attributes set when the
>>> context was created.  If the attributes are compatible, the existing
>>> context
>>> object must be returned.  If the attributes are not compatible,
>>> getContext()
>>> must raise an INVALID_STATE_ERR exception.
>>>
>>> If multiple rendering contexts are active, they all render to the same
>>> canvas bitmap; they are not layered or otherwise isolated.  Changes made
>>> to
>>> the canvas bitmap with one context must be immediately visible to any
>>> other
>>> active contexts on the canvas.  It is up to the implementation to manage
>>> synchronization issues associated with rendering with different contexts
>>> to
>>> the same canvas.
>>>
>>
>> Sorry for not replying earlier.
>>
>> I don't think the results of last week's conference call are captured
>> in the text above, so here is a concrete example of why I think the
>> context attributes should always be treated as a hint, and why the
>> getContext() call should not throw an exception for incompatible
>> attributes.
>>
>
> Yep, my bad -- I didn't get a chance to fiddle with this some more since the
> last call.
>
>> If the call to getContext() can throw an exception, and you combine
>> multiple WebGL libraries that request incompatible attributes, then
>> each library needs to write code like this:
>>
>>   var attrs = { ... };
>>   var canvas = ...;
>>   var gl;
>>   try {
>>     gl = canvas.getContext("webgl", attrs);
>>   } catch (e) {
>>     gl = canvas.getContext("webgl");
>>   }
>>   if (!attrsAreSufficient(gl.getContextAttributes())) {
>>     throw "The GL context was created with incompatible attributes";
>>   }
>>
>> If we specify instead that getContext() will always return a context
>> object if multiple contexts are supported by the implementation, then
>> the code is simplified to this:
>>
>>   var attrs = { ... };
>>   var canvas = ...;
>>   var gl = canvas.getContext("webgl", attrs);
>>   if (!attrsAreSufficient(gl.getContextAttributes())) {
>>     throw "The GL context was created with incompatible attributes";
>>   }
>>
>> Basically, libraries requesting specific attributes will always need
>> to check to see whether or not they can work with the attributes that
>> may have been set up by another library. While I understand the desire
>> to fail early and fast, in this case doing so only adds burden to the
>> programmer. Note that the verification logic is the same in the two
>> versions above; the second one simply has fewer lines of boilerplate
>> code around it.
>>
>> Also, there will be context attribute permutations that can not be
>> supported by any current FBO-based WebGL implementation, such as
>> "depth=false stencil=true". Rather than throw exceptions in these
>> cases, I think it is better to create the context with the closest
>> compatible set of attributes. The distinction is similar to the
>> differences in behavior between GLX and WGL/CGL (Mac OS X). GLX's
>> fail-fast visual and FBConfig selection behavior is more precise, but
>> is also more difficult to program to.
>>
>
> I'm slowly coming around to this; I still don't really like it, but I don't
> see a way around it... forcing the author to write the code in your first
> example doesn't seem too bad, but I also can't convince myself that there's
> any benefit to them doing so.  There are really two separate problems that
> we're dealing with, which is initial context creation and subsequent context
> getting.  One disadvantage of this approach is that if your app/library can
> handle two different paths, but they're distinct (e.g. maybe one with
> stencil and no depth buffer, and the other with a depth buffer and no
> stencil), you have no way of requesting the other if the first fails.  I
> guess in that case you'd request both stencil and depth though, so maybe
> that's not an issue as long as developers always request the union of their
> needed features.
>
> What do others think of this?  That is, specifically making the context
> attributes entirely optional and ignorable by getContext, which should
> always return either null if the context isn't supported at all or a context
> object?

During today's conference call I received an action item to post
examples of code using the three API variants proposed so far:

  1. Adding an explicit createContext(); getContext() never implicitly
creates a context
  2. Subsequent calls to getContext() throw when called with different
attributes than the first time
  3. getContext() never throws

Here is the code the developer would need to write for case (1):

  var canvas = ...;
  var attrs = { ... };
  var gl = canvas.getContext("webgl");
  if (gl) {
    if (!attrsAreSufficient(gl.getContextAttributes())) {
      throw "The GL context was created with incompatible attributes";
    }
  } else {
    gl = canvas.createContext("webgl", attrs);
  }

Here is the code the developer would need to write for case (2):

  var canvas = ...;
  var attrs = { ... };
  var gl;
  try {
    gl = canvas.getContext("webgl", attrs);
  } catch (e) {
    gl = canvas.getContext("webgl");
  }
  if (!attrsAreSufficient(gl.getContextAttributes())) {
    throw "The GL context was created with incompatible attributes";
  }

Finally, here is the code the developer would need to write for case (3):

  var canvas = ...;
  var attrs = { ... };
  var gl = canvas.getContext("webgl", attrs);
  if (!attrsAreSufficient(gl.getContextAttributes())) {
    throw "The GL context was created with incompatible attributes";
  }

While I appreciate the desire to have precise information about
whether a given context type already exists on a canvas or whether it
was just created, I also think that this is more information than
necessary. Please note that the "attrsAreSufficient()" call needs to
be present when working with *all three* API variants to handle
library interoperability. The only question is how much additional
boilerplate code is necessary.

This having been said, here is proposed spec text for API variant (3),
based on Vlad's earlier text.

  object getContext(in DOMString contextId, in optional any attributes)

  A canvas may be rendered to using one or more contexts, each named by
  a string context ID. For each canvas, there is a set of zero or more
  active contexts. The getContext() method is used to obtain a
  particular rendering context for the canvas.

  'contextId' must be a string naming a canvas rendering context to be
  returned. For example, this specification defines the '2d' context,
  which, if requested, will return either a reference to an object
  implementing CanvasRenderingContext2D or null, if a 2D context cannot
  be created at this time. Other specifications may define their own
  contexts, which would return different objects.

  The optional 'attributes' parameter must be either unspecified or an
  object specific to the context being requested. An unspecified value
  indicates a default set of attributes, as defined by the context
  ID. Unknown attributes must be ignored by the context.

  If getContext() is called with a context ID that the implementation
  does not support, it must return null.

  If there are no active contexts for the canvas, the implementation
  must create the specified context for the canvas.

  If a context ID that is already an active context for the canvas is
  requested, then any passed attributes must be ignored, and a reference
  to the existing context object must be returned.

  If there are one or more active contexts and a context ID that is not
  currently active is requested, it is up to the implementation to
  determine whether the requested context can be used simultaneously
  with all currently active canvas contexts. If simultaneous rendering
  with the requested context is not possible, getContext() must return
  null. Otherwise the implementation must create the specified context
  for the canvas.

  Certain context types may not support all combinations of
  context-specific attributes. If an unsupported set of attributes is
  requested during context creation, but the context ID is otherwise
  compatible with all existing contexts, then the implementation must
  create the new context with a set of attributes that best satisfies
  those requested. The caller is responsible for using context-specific
  APIs to determine whether the attributes used to create the context
  satisfy the requirements of the caller's code.

  If a new context is successfully created, a reference to an object
  implementing the context API is returned and the new context is added
  to the list of active contexts for the canvas.

  If multiple rendering contexts are active, they all render to the same
  canvas bitmap; they are not layered or otherwise isolated. Changes
  made to the canvas bitmap with one context must be immediately visible
  to any other active contexts on the canvas. The implementation must
  manage synchronization issues associated with rendering with different
  contexts to the same canvas.

Comments?

-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: