I've recently viewed N3888. I've got a few issues with this that I'd like to raise.
First, we need to start with the motivation for this paper. The problem is that virtually all of the listed example use cases require massive amounts of functionality not provided. There's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability. Not to mention all of the truly vast support code that would be required to handle some of the proposed use cases, also not provided, some of which goes beyond merely support. For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support? The proposed functionality is a drop in the proverbial bucket, and a waste of the Committee's time.
Second, the design decisions presents little justification for choosing Cairo. The fact that it has been used in places like Firefox is essentially just an appeal to authority fallacy, where the authority is unnamed Firefox developers. There are undoubtedly innumerable projects that use Singletons all over the place, but they should not be Standardised. The Motivation page lists several available choices for developers, and basing an API on one of them isn't even considered.
It's stated that application of mechanical rules can convert the Cairo API into a C++ API. This makes the process sound simple and easy, when in reality, it's anything but. The mechanical rules are several pages of Standardese. Furthermore, the benefits of mechanical transformation aren't discussed. The effort in performing a manual translation would be comparatively minimal, and would produce results that would be of substantially higher quality.
When discussing the choice to use Cairo, the output of the mechanical translator is described as an object-orientated C++ API. This is an extremely charitable description at best. For simple example, the numerous POD structs which have no constructors. And matrix, which has no constructors but plenty of two-phase initialization methods, and no operator overloads. The error handling facilities are also extremely primitive. drawing_exception doesn't really contain any useful data. If I attempt to load a font and get "user_font_error", this is not going to enable me to solve the problem, because I have no useful data about that problem.
The context object is the very epitome of evil. Even OpenGL has been moving away from this stuff- they cut the matrix stack and are standardising DSA. Using it essentially involves keeping the current state imagined in my head whilst I manually push and pop off some stack hidden somewhere. I set all the state to some invisible variable somewhere, hope nobody else needed these essentially global variables, and then try to use it. What are the concurrency guarantees involved in these methods? How is my compiler going to optimize pushes and pops off a stack on the heap somewhere else, instead of on my function-local stack?
Using Cairo and then fixing all of these issues so that the API was of a sufficient quality to be Standardised would be equivalent to just starting from scratch. A much better start would be the latest generation of Microsoft APIs. Not every aspect of all of them is relevant, but as a group, they are generally capable and far better designed. For example, DirectWrite includes proper Unicode rendering support, and ID3D11Device/ID3D11DeviceContext design solves the issue of concurrency. The mathematical support libraries aren't perfection but they are at least basically competent.
Thirdly, the native handles issue is not as simple as it first appears. The issue of threading is vastly different to the issue of rendering. There are far fewer useful implementations of a threading API per platform. Virtually all threading implementations on Windows will offer a Win32 thread handle as a native handle, for example. This is not true of rendering, which could have several reasonable implementations. There are far fewer useful operations on threads themselves. And finally, the use of a thread does not often depend on other related objects. For example, if I have an implementation backed by DX11, and I have an ID3D11DeviceContext, this is useless to me without an ID3D11Device. Mutating that device context would be extremely risky. The implementation cannot just return a pointer for me to mutate at will- virtually every operation would destroy the rendering state on which it depends. The implementation needs to know when I am drawing, when I am done, what resources I used, and all of that before they are even created. Many usages require creation flags to support them, for example D3DUSAGE_DYNAMIC. In this case, the implementation would effectively need to know my intentions ahead of time. This information is not exposed through a simple native_handle() scheme.
Abstract platform groups is another matter, though. It's been fifteen years since Glide died, and no new serious contenders have risen. Whilst Mantle is in a unique position here, it's also well out of the target groups. Every platform that supports Mantle will also support DX or OGL. Mantle users are explicitly looking for a low-level, direct-to-GPU approach and are not going to be interested in the Committee's abstraction. And it will be years before it is obvious whether or not it's worth serious attention. However, more generally, the issue is less about the raw underlying API, but more about the underlying hardware. No matter what drawing API is used, it is impossible to port an application from Windows desktop to Windows Phone simply by rebuilding it. The entire user interface must be redesigned to provide a positive user experience.
Ultimately, what this really comes down to is a lack of focus on the motivation. If the motivation is to provide for programmers to produce simple interactive applications with C++, then the proposal need not concern itself with details like what APIs are used or even, to a fair extent, what the result should look like. It should focus on issues like creating windows, providing for Unicode input, processing, and output, providing for common controls, touch and mouse input, concurrency, and such issues. It's simple enough to provide something like the D3DControl that WPF has on top of that for user-provided drawing. This would be vastly more useful than solving the non-problem of having to use an external drawing API given an external drawing API, external Unicode support, external input, etc.
N3888 is fundamentally broken, both in motivation, and implementation.
--
You received this message because you are subscribed to the Google Groups "Graphics" group.
To unsubscribe from this group and stop receiving emails from it, send an email to graphics+u...@isocpp.org.
To post to this group, send email to grap...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/graphics/.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/graphics/59bf464f-1b98-4108-bed1-c714e20a61f6%40isocpp.org.
I've recently viewed N3888. I've got a few issues with this that I'd like to raise.
First, we need to start with the motivation for this paper. The problem is that virtually all of the listed example use cases require massive amounts of functionality not provided. There's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability. Not to mention all of the truly vast support code that would be required to handle some of the proposed use cases, also not provided, some of which goes beyond merely support. For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support? The proposed functionality is a drop in the proverbial bucket, and a waste of the Committee's time.
The listed example uses cases are these: "Application programmers write programs that often need to render or display basic 2D graphics, including for introductory examples. Some need to display images. Some need to create simple charts and graphs. Some need to display text beyond the capabilities offered by the C++ console. Many application types call for all three of these capabilities along with the ability to interact with them using keyboard, mouse, and (more and more) touch.". With the exception of the last sentence I'm afraid I don't see anything that "require[s] massive amounts of functionality not provided." And for the last sentence, the paper acknowledges that this functionality is missing a few paragraphs later: "The scope of this proposal is limited to 2D drawing. It is expected that there will be one or more additional proposals which will add additional features such as the ability to capture and process keyboard, mouse, and touch input.".
As for your statement that "[t]here's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability", I again must profess that I simply do not know what "bunch of platform-specific APIs" you think are needed. If you were to provide some specifics I would try to address them. That said, even conceding that point arguendo I disagree with it. I think that adding a standard 2D drawing API when applications which use it will also require non-standard code is beneficial. 2D drawing is a reasonably self-contained domain and one which is used on a great many platforms for a great many purposes. As such it is both relatively easy to standardize (because it is contained) and beneficial to standardize (because it is used so often). To me the question was "can it be standardized?" and the answer, after examining various cross-platform drawing APIs (e.g. cairo, Qt's QPainter, openFrameworks, and cinder) was yes.
"For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support?" The answer is that we did propose such an interface so the question of how we propose to do it is moot. The interface in question accepts UTF-8 strings. Implementations are required to render them to the same extent that Cairo's toy font API does. Implementers are encouraged to go beyond this and provide support for RTL, BiDi, proper kerning (e.g. for scripts such as Devanagari), etc. But we felt that even providing basic text rendering was a step in the right direction. If someone wishes to propose a more advanced API, I encourage them to do so as it would most certainly be useful.The API as it stands now could be implemented using anything from bitmap fonts to something like DirectWrite. I consider this a good thing since it makes it possible for even hosted implementations to consider implementing this library if they need basic 2D drawing capabilities while staying within strict resource constraints. We never considered attempting to include a standardization of Unicode since it would be A) beyond the scope of SG 13; and B) likely to be contentious. While we are willing to spend time and see this process through, however long it takes, there is no reason to include something that is, at best, tangential that would almost assuredly take many years. In short, we saw no reason to sink our own ship by overloading it with someone else's cargo.
Second, the design decisions presents little justification for choosing Cairo. The fact that it has been used in places like Firefox is essentially just an appeal to authority fallacy, where the authority is unnamed Firefox developers. There are undoubtedly innumerable projects that use Singletons all over the place, but they should not be Standardised. The Motivation page lists several available choices for developers, and basing an API on one of them isn't even considered.
We chose cairo because "[it] provides cross-platform support for advanced 2D drawing... has demonstrated that it is implementable... [and] has a mature API which is... object-oriented in its design." There is a page and a half of more detailed reasoning. But the simple reason is that it met our goals. That does not mean that other libraries and APIs did not meet our goals. Simply that cairo did and so we chose it. I could have drafted a QPainter-based API but it would've been very difficult to separate 2D drawing from the other parts of Qt and we didn't want to try to standardize more than was required for basic 2D graphics rendering and display.
As for the claim that mentioning Firefox "is essentially just an appeal to authority fallacy", you have misapprehended our reasons for mentioning it. We mentioned that cairo is used by Firefox, Mono, and GTK+ because we wished to demonstrate to the Committee that well-known, cross-platform projects have successfully used cairo. It was stated as evidence of our claims about its cross-platform utility and advanced 2D drawing capabilities. We chose to mention projects that we expected Committee members to know. If you believe that the usage of cairo in these projects is trivial or that the maintainers of these projects are dissatisfied with their choice, by all means present your evidence. We did not discover any such evidence and in fact had various people we consider experts in this field praise cairo. If there are reasons not to use it we want to know them and we want the Committee to know them. So please do provide any negative evidence you may have, if any.
As for the analogy to singletons, they are a design pattern not a library and so the analogy does not really hold together in my view. Regardless, thread-safe function local static initialization (sometimes called "magic statics") are something that, among other things, makes using the singleton pattern practical in C++ and it was added to the Standard. Lastly, your argument about singletons could have been made about dynamically resizeable arrays, doubly-linked lists, and FIFO containers, yet vector, list, and stack are all part of the Standard Library.
It's stated that application of mechanical rules can convert the Cairo API into a C++ API. This makes the process sound simple and easy, when in reality, it's anything but. The mechanical rules are several pages of Standardese. Furthermore, the benefits of mechanical transformation aren't discussed. The effort in performing a manual translation would be comparatively minimal, and would produce results that would be of substantially higher quality.We indeed do not have a design decisions section discussing the choice of mechanical transformation. I can't say that it ever occurred to me that one was needed. When something can be done by following a set of rules, then provided that the rules themselves are satisfactory, the results should prove consistent, thus eliminating the possibility of differing interpretations. That, by the way, is why the rules are several pages of Standardese. Precise language is required for such rules if consistency is to be achieved. Indeed the thing that concerns me the most is that there may be some ambiguity somewhere in the rules that I missed. If so I very much hope that folks from the Committee will identify any such problems so that they can be resolved.As for a manual translation, I created such an API prior to the decision to use Cairo. I had a working implementation with much of the functionality. Then in Chicago Beman Dawes, a very wise person, suggested that we start from an existing, known API (he then wrote up a paper containing his suggestions; it is cited at the end of our proposal). At first I pressed on with my API since it was progressing nicely and I felt that it was clean and elegant. I still do, for that matter. But the wisdom of his words gradually penetrated my dense skull as I observed various debates about the relative merits of different approaches to various issues. At the Redmond meeting (notes cited at the end of the proposal), the last of my resistance to dropping my initial work and starting anew collapsed and Jason, Herb, and I explored options and decided on cairo.
I've recently viewed N3888. I've got a few issues with this that I'd like to raise.
First, we need to start with the motivation for this paper. The problem is that virtually all of the listed example use cases require massive amounts of functionality not provided. There's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability. Not to mention all of the truly vast support code that would be required to handle some of the proposed use cases, also not provided, some of which goes beyond merely support. For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support? The proposed functionality is a drop in the proverbial bucket, and a waste of the Committee's time.
The listed example uses cases are these: "Application programmers write programs that often need to render or display basic 2D graphics, including for introductory examples. Some need to display images. Some need to create simple charts and graphs. Some need to display text beyond the capabilities offered by the C++ console. Many application types call for all three of these capabilities along with the ability to interact with them using keyboard, mouse, and (more and more) touch.". With the exception of the last sentence I'm afraid I don't see anything that "require[s] massive amounts of functionality not provided." And for the last sentence, the paper acknowledges that this functionality is missing a few paragraphs later: "The scope of this proposal is limited to 2D drawing. It is expected that there will be one or more additional proposals which will add additional features such as the ability to capture and process keyboard, mouse, and touch input.".
The first issue here is "Many". As far as I can see, you might as well say "Virtually all". I can hardly think of any useful utilities that draw images that don't do so interactively. I mean, correct me if I'm wrong here, but the Motivation section strongly implies "We'd like these cases to be written virtually or entirely in Standard-compliant code rather than external APIs".
The second issue here is interoperation. I'm not going to go around using QString, QButton, QWindow, and then std::drawing. It would be immeasurably simpler to use Qt for all these needs. For example, what if QButton is painted with OGL and std::drawing is implemented with DirectX? It would be vastly more reliable for me to stick to Qt for everything. There are similar decisions for deciding to use Microsoft APIs (especially in light of airspace issues that they love to throw in). Providing only one of these components means that I have no guarantee that it will work with any of the others, plus I'm still hard-coupled to whoever is providing them, like Windows or Qt. Even if it turns out that Qt uses OGL and my implementation of std::drawing uses OGL, using std::drawing isn't improving my situation at all- it's made it even worse, since I'm now dependent on an implementation detail and my code could never function on some other implementation that uses DirectX or GDI or something.
As for your statement that "[t]here's absolutely no useful purpose in a Standard 2D drawing API, when in order to achieve any of the motivating use cases, I will also need a bunch of platform-specific APIs or other abstractions, with questionable interoperability", I again must profess that I simply do not know what "bunch of platform-specific APIs" you think are needed. If you were to provide some specifics I would try to address them. That said, even conceding that point arguendo I disagree with it. I think that adding a standard 2D drawing API when applications which use it will also require non-standard code is beneficial. 2D drawing is a reasonably self-contained domain and one which is used on a great many platforms for a great many purposes. As such it is both relatively easy to standardize (because it is contained) and beneficial to standardize (because it is used so often). To me the question was "can it be standardized?" and the answer, after examining various cross-platform drawing APIs (e.g. cairo, Qt's QPainter, openFrameworks, and cinder) was yes.
Many things can be Standardized. We could introduce std::singleton<T>. We could introduce a std::matrix which, when constructed, sometimes wipes the user's hard drive and sometimes acts like a 4x4 matrix of floats. We can Standardise a component that facilitates for the introduction of a keylogger. But none of these things should be Standardised.
2D drawing is self-contained, except that you have to draw everything with the same drawing API, including if I want to interoperate with some 3D drawing somewhere, so if I ever intend to draw anything (e.g. user interface) then I need to know they're compatible. And if you want to draw Unicode text then you have to implement Unicode processing facilities, for example, line breaking Unicode text. And separating text into grapheme clusters so you can find the grapheme from the font. Which includes normalization. And it also involves validating the Unicode so that you don't try to end up rendering something illegal. So basically, it would be impossible to implement rendering Unicode text without implementing lots of Unicode algorithms. So you'd require implementers to implement it; but not provide it for users to use.
So it's completely not self contained at all. You'd require implementations to implement quite a lot of functionality in other areas, plus the implementation details are serious user-facing issues. This doesn't sound good at all.
"For example, how on earth do the authors propose an interface to render text, when the Standard possesses no useful Unicode support?" The answer is that we did propose such an interface so the question of how we propose to do it is moot. The interface in question accepts UTF-8 strings. Implementations are required to render them to the same extent that Cairo's toy font API does. Implementers are encouraged to go beyond this and provide support for RTL, BiDi, proper kerning (e.g. for scripts such as Devanagari), etc. But we felt that even providing basic text rendering was a step in the right direction. If someone wishes to propose a more advanced API, I encourage them to do so as it would most certainly be useful.The API as it stands now could be implemented using anything from bitmap fonts to something like DirectWrite. I consider this a good thing since it makes it possible for even hosted implementations to consider implementing this library if they need basic 2D drawing capabilities while staying within strict resource constraints. We never considered attempting to include a standardization of Unicode since it would be A) beyond the scope of SG 13; and B) likely to be contentious. While we are willing to spend time and see this process through, however long it takes, there is no reason to include something that is, at best, tangential that would almost assuredly take many years. In short, we saw no reason to sink our own ship by overloading it with someone else's cargo.
I've already described how you essentially already are anyway. But what I think is more important is that if you actually address those issues, you would end up with something that I feel would address more useful use cases. Pretty much the only thing you can do right now is blindly render to a file or something- pretty much all the user-facing use cases are out the window due to airspacing and other complications.
Second, the design decisions presents little justification for choosing Cairo. The fact that it has been used in places like Firefox is essentially just an appeal to authority fallacy, where the authority is unnamed Firefox developers. There are undoubtedly innumerable projects that use Singletons all over the place, but they should not be Standardised. The Motivation page lists several available choices for developers, and basing an API on one of them isn't even considered.
We chose cairo because "[it] provides cross-platform support for advanced 2D drawing... has demonstrated that it is implementable... [and] has a mature API which is... object-oriented in its design." There is a page and a half of more detailed reasoning. But the simple reason is that it met our goals. That does not mean that other libraries and APIs did not meet our goals. Simply that cairo did and so we chose it. I could have drafted a QPainter-based API but it would've been very difficult to separate 2D drawing from the other parts of Qt and we didn't want to try to standardize more than was required for basic 2D graphics rendering and display.
Anyone reading the proposed API can clearly determine that it is neither mature, nor object orientated. It would be difficult to find a better definition of what is not those things. There are many drawing APIs which are implemented and support drawing, many of which are a bit (not necessarily always a lot) closer to mature object-orientated approaches. (Also, it's hard to display images without for example windows, and displaying them doesn't have a huge quantity of meaning without user input).
As for the claim that mentioning Firefox "is essentially just an appeal to authority fallacy", you have misapprehended our reasons for mentioning it. We mentioned that cairo is used by Firefox, Mono, and GTK+ because we wished to demonstrate to the Committee that well-known, cross-platform projects have successfully used cairo. It was stated as evidence of our claims about its cross-platform utility and advanced 2D drawing capabilities. We chose to mention projects that we expected Committee members to know. If you believe that the usage of cairo in these projects is trivial or that the maintainers of these projects are dissatisfied with their choice, by all means present your evidence. We did not discover any such evidence and in fact had various people we consider experts in this field praise cairo. If there are reasons not to use it we want to know them and we want the Committee to know them. So please do provide any negative evidence you may have, if any.
It's not my job to suggest that the maintainers of Firefox are unhappy with Cairo. It's your job to show that they are happy with Cairo. Even if they are, that's a very long way away from suitable for Standardisation. For a simple example, Google's style guide forbids exceptions, and no doubt they're quite happy with exception-less libraries for this reason, but that would be a fairly major negative in weighting an API for Standardisation, not a positive. How did Firefox solve the issue of different implementations and airspacing, for example? How does Firefox handle concurrency with Cairo? How do they handle interoperation with their other technologies? Did they have to duplicate a bunch of Unicode functionality? Stating that Firefox uses Cairo, which is what is done in the proposal, is a very, very long way from meaningful support for the proposal.
If you've had experts in the field praise Cairo, then show it. Tell me how many you asked; who they were; and exactly how each of them responded (Also, try not to confuse "Implemented new anti-aliasing algorithm" with "Designed Standard-quality APIs", since they're entirely different fields).
As for the analogy to singletons, they are a design pattern not a library and so the analogy does not really hold together in my view. Regardless, thread-safe function local static initialization (sometimes called "magic statics") are something that, among other things, makes using the singleton pattern practical in C++ and it was added to the Standard. Lastly, your argument about singletons could have been made about dynamically resizeable arrays, doubly-linked lists, and FIFO containers, yet vector, list, and stack are all part of the Standard Library.
It absolutely could, and it absolutely should. Those things should not have been Standardised just because they could be or just because people use them. They should have been Standardised because virtually all users of the language need them, and because implementing them yourself in a safe and performant manner is actually extremely difficult (still finding exception safety bugs in MSVC2013's vector and poor performance with their deque). Also because most hand-rolled containers, as far as I'm aware, had an abysmal design and the STL was actually a big improvement over them. Also because they are common vocabulary types between libraries. On the other hand, just "Use Cairo directly if you like Cairo" is not especially difficult and carries many advantages over Standardising Cairo. Such as, "Since my 3D content is rendered with DX11, I will use D2D and DWrite instead of Cairo to guarantee correct interoperability". Or "Since I am using Qt for basically everything else, I will use QPainter".
It's stated that application of mechanical rules can convert the Cairo API into a C++ API. This makes the process sound simple and easy, when in reality, it's anything but. The mechanical rules are several pages of Standardese. Furthermore, the benefits of mechanical transformation aren't discussed. The effort in performing a manual translation would be comparatively minimal, and would produce results that would be of substantially higher quality.We indeed do not have a design decisions section discussing the choice of mechanical transformation. I can't say that it ever occurred to me that one was needed. When something can be done by following a set of rules, then provided that the rules themselves are satisfactory, the results should prove consistent, thus eliminating the possibility of differing interpretations. That, by the way, is why the rules are several pages of Standardese. Precise language is required for such rules if consistency is to be achieved. Indeed the thing that concerns me the most is that there may be some ambiguity somewhere in the rules that I missed. If so I very much hope that folks from the Committee will identify any such problems so that they can be resolved.As for a manual translation, I created such an API prior to the decision to use Cairo. I had a working implementation with much of the functionality. Then in Chicago Beman Dawes, a very wise person, suggested that we start from an existing, known API (he then wrote up a paper containing his suggestions; it is cited at the end of our proposal). At first I pressed on with my API since it was progressing nicely and I felt that it was clean and elegant. I still do, for that matter. But the wisdom of his words gradually penetrated my dense skull as I observed various debates about the relative merits of different approaches to various issues. At the Redmond meeting (notes cited at the end of the proposal), the last of my resistance to dropping my initial work and starting anew collapsed and Jason, Herb, and I explored options and decided on cairo.
I read N3825. It doesn't discuss why this approach was taken at all. It just says "We chose Cairo, then we created some mechanical rules". The main issues that I'm seeing here with the mechanical approach are firstly, it seems to me that you've practically put more effort into the mechanical rules already than would be necessary to simply derive a C++ API from Cairo manually, and secondly, the output is still embarrassingly low quality and would need substantial work before being suitable for Standardisation (even ignoring all the other issues I've raised).