N3888 - A Proposal to Add 2D Graphics Rendering and Display to C++

490 views
Skip to first unread message

Michael McLaughlin

unread,
Jan 20, 2014, 6:14:31 PM1/20/14
to grap...@isocpp.org
Herb Sutter, Jason Zink, and I have been working to turn Jason's meeting notes (N3825) from the Nov. 21 Redmond Meeting into a proposal. We were able to wrap it up just in time for the pre-meeting mailing for the ISO C++ Committee's Issaquah meeting (PDF) coming up in February. You can access it here: http://isocpp.org/blog/2014/01/n3888 .
 
I'll post a link to the Git repository for the reference implementation once it is ready (it's feature complete; there's just some clean up work to do).
 
Note that though this is a proposal which we are expecting to present (I'll be at the conference from Monday afternoon through Wednesday), it is not final. We hope and expect to get a lot of great feedback from the committee members and from all of you as well.
 
Keep in mind as you read it that the goal for this proposal was to create a fairly conservative mechanical transformation of the cairo API. We expect it to change and evolve (and there is always a (hopefully small) chance that the approach will be rejected entirely).
 
We look forward to your feedback, either here, on the blog post linked to above, on std-discussion, on std-proposals, or in person in Issaquah (if you can make it). Thanks!
 
-Mike

Vadim Zeitlin

unread,
Jan 21, 2014, 11:27:07 AM1/21/14
to grap...@isocpp.org
On Tuesday, January 21, 2014 12:14:31 AM UTC+1, Michael McLaughlin wrote:
> Herb Sutter, Jason Zink, and I have been working to turn Jason's meeting notes (N3825) from the Nov. 21 Redmond Meeting into a proposal.
...
> We look forward to your feedback

Hello,

 This is probably not exactly the kind of constructive feedback you were
looking to, but I'd like to mention that personally I strongly believe that
the idea of standardizing one, and by no means obviously the "best",
existing 2D drawing library, is simply not the correct approach. You reject
the idea of creating a new API with nothing more than

> Unfortunately this would not have implementation and usage experience

but this is not convincing at all. We do have experience with both
implementing and using such APIs, e.g. one example that I personally know
well is wxGraphicsContext[*] which efficiently maps to Cairo, CoreGraphics
and GDI+, but this is certainly not the only one. I don't mean to imply that
wxGraphicsContext is the API that should be standardized as it's by no means
perfect, but it does provide an immediate counterexample to the point above.

 And you don't give any other good reasons for _not_ creating a good
platform-independent drawing API, whereas there are several obvious
advantages to doing it.

 I hope the entire approach can be reconsidered and IMO it would be better
to not have any standard graphics API than to standardize on Cairo. As great
as Cairo can be, it's not obviously (or perhaps even obviously not) the
best choice neither under Microsoft Windows nor OS X.

 Regards,
VZ

[*] http://docs.wxwidgets.org/trunk/classwx_graphics_context.html

Ville Voutilainen

unread,
Jan 21, 2014, 11:32:30 AM1/21/14
to grap...@isocpp.org
On 21 January 2014 18:27, Vadim Zeitlin <vzei...@gmail.com> wrote:
> And you don't give any other good reasons for _not_ creating a good
> platform-independent drawing API, whereas there are several obvious
> advantages to doing it.

I do not see which part of the planned 2-d API is not platform-independent,
and I don't know which parts of it are "not good".

> I hope the entire approach can be reconsidered and IMO it would be better
> to not have any standard graphics API than to standardize on Cairo. As great

The plan of SG13 is not to standardize Cairo. The plan is to standardize an
API that can use Cairo, or GDI+, or CoreGraphics, underneath.

Vadim Zeitlin

unread,
Jan 21, 2014, 12:03:35 PM1/21/14
to grap...@isocpp.org
On Tue, 21 Jan 2014 18:32:30 +0200 Ville Voutilainen <ville.vo...@gmail.com> wrote:

VV> On 21 January 2014 18:27, Vadim Zeitlin <vzei...@gmail.com> wrote:
VV> > And you don't give any other good reasons for not creating a good
VV> > platform-independent drawing API, whereas there are several obvious
VV> > advantages to doing it.
VV>
VV> I do not see which part of the planned 2-d API is not platform-independent,
VV> and I don't know which parts of it are "not good".

We can go into the latter in details if there is any chance of something
useful coming out of it, but I don't know if it's really worth doing it
now, is it? As a broad hint, I'd say that just about everything font/text-
related in Cairo is, if not "not good", then at least "not great".

VV> > I hope the entire approach can be reconsidered and IMO it would be better
VV> > to not have any standard graphics API than to standardize on Cairo. As great
VV>
VV> The plan of SG13 is not to standardize Cairo. The plan is to standardize an
VV> API that can use Cairo, or GDI+, or CoreGraphics, underneath.

I realize this, thanks. However I also realize -- and thought that so did
everyone else, sorry for not making it explicit -- that standardizing on
Cairo API would make all possible implementations

1. Limited to only the features supported by Cairo.
2. Less than optimally efficient for those not using Cairo itself.

And I think that creating a new API is the only way to avoid these
problems.

Regards,
VZ

Michael McLaughlin

unread,
Jan 21, 2014, 12:10:48 PM1/21/14
to grap...@isocpp.org
This is one of the kinds of feedback that I was hoping for. You've identified a weakness in our Design Decisions sections. When I wrote the part discussing synthesizing a new API, I was unconsciously relying on the reader to be familiar with N3791 - http://isocpp.org/files/papers/n3791.html . This was a mistake on my part and it should have been explicitly cited there and perhaps even briefly summarized. I am not sure if we will publish an update pre-conference (I need to consult my co-authors), but I am going to modify that section to try to address your feedback. So thank you!
 
-Mike
 


--
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/1393790c-ae1d-4248-9a6f-108d9747efc2%40isocpp.org.

Klaim - Joël Lamotte

unread,
Jan 21, 2014, 12:23:18 PM1/21/14
to grap...@isocpp.org
My current thinking about this proposal is "well at least there is now a starting point".
Here are some remarks/questions:

1. About "Usage of Shared Ownership Semantics":
Did you explore the additional possibility of just not implying any kind of copy or sharing semantic at all for these types?
Taking your example:

X x1;
auto x2 = x1; // compilation error: copy is forbidden

Thus letting the user to define when, where and how to share these objects if at any moment it is proven necessary?
I suspect that hiding the sharing without providing a separate type for sharing (like future/shared_future) might give the wrong assumptions to user, 
like that he can use these objects from different threads safely with minimal issues.
I feel that if sharing of some of these objects is necessary, it should be the user that setup the sharing mechanism specific to his/her use case and constraints.

That being said, that's just a feeling so I'm wondering.

2. I do agree that starting with Cairo provide a necessary starting point. I do not agree that the current proposal is complete or good enough to 
fill the need. One thing that highly bother me is that the result of the mechanical transformation really lack any use of C++ idioms, which 
are historically avoided by most graphic apis except the ones from very recent frameworks.
Basically, I feel that from this proposal, there is a need for a lot of manual modifications to match something useful for C++ programmers.
This is not an argument though, I'm still looking at the details to see why I don't feel comfortable with the result of the transformation in details.

3. Am I correct that in the current state of this proposal, the user can draw something in a surface, but can't do anything with that surface afterward?
The only thing I see is "write to png" function but there is no way to access the raw data to exploit the surface content.
Maybe something like write_to_buffer() would help? or provide direct access like a vector.data()?

4. That pose the question of the basic units used in Cairo. I see int double etc. but no definition of what is a pixel.
I suppose that there is a lot of work to do there.

5. I suggest removing "user data", or is there a reason to keep it?


That's all for now but I'm looking at details in more depth.


Michael McLaughlin

unread,
Jan 21, 2014, 12:41:39 PM1/21/14
to grap...@isocpp.org
VV> >  And you don't give any other good reasons for not creating a good
VV> > platform-independent drawing API, whereas there are several obvious
VV> > advantages to doing it.
VV>
VV> I do not see which part of the planned 2-d API is not platform-independent,
VV> and I don't know which parts of it are "not good".

 We can go into the latter in details if there is any chance of something
useful coming out of it, but I don't know if it's really worth doing it
now, is it? As a broad hint, I'd say that just about everything font/text-
related in Cairo is, if not "not good", then at least "not great".

 
I think it is worth doing. To me this proposal is not a final draft. When it comes to fonts and text, our choice, given the goals of A) avoiding platform dependencies; and B) sticking to a mechanical transformation from cairo, was to either have no font and text support or to incorporate the cairo toy font API (we briefly discussed cairo's user font API, but as it's just composed of a series of callbacks, we decided not to include it in the initial proposal). We chose to use the toy font API because we wanted some way to display text. Cairo's implementation of the toy font API is very simple. But that is an implementation detail. During discussions, one of the cairo maintainers wrote that there was no reason the toy font API implementation couldn't be improved to support RTL, BiDi, Devanagari-like scripts, etc. Though the API is simple, I think that as an API it is not so simple. But font management and text layout and rendering is one area we definitely hope to get some expert feedback on.
 

VV> >  I hope the entire approach can be reconsidered and IMO it would be better
VV> > to not have any standard graphics API than to standardize on Cairo. As great
VV>
VV> The plan of SG13 is not to standardize Cairo. The plan is to standardize an
VV> API that can use Cairo, or GDI+, or CoreGraphics, underneath.

 I realize this, thanks. However I also realize -- and thought that so did
everyone else, sorry for not making it explicit -- that standardizing on
Cairo API would make all possible implementations

1. Limited to only the features supported by Cairo.
2. Less than optimally efficient for those not using Cairo itself.

 And I think that creating a new API is the only way to avoid these
problems.

As for 1., this was by design. Cairo represents a nice cross-section of what is available on the most widely used platforms. We did not want to introduce features that are missing or impossible to do on any of the major platforms. As for 2., I don't think the cairo API is particularly bad. Any API that isn't directly interfacing with the hardware is going to be less than optimally efficient. So the question then is whether cairo is particularly poorly designed. Having used and researched various APIs, in my experience each has good points and not-so-good points. I don't feel that designing a new API will produce a better result than using cairo as a starting point (and modifying the resulting transformation where necessary to improve the overall result). Additionally, since using cairo directly would be introducing a layer of middleware between the proposal and the actual rendering technology, in many cases using cairo itself would be less than optimally efficient due to the extra layer of calls, data type transformations, etc.
 
If I felt that creating a new API would be obviously superior, I would not have put my original work on indefinite hiatus (see: https://groups.google.com/a/isocpp.org/forum/#!topic/graphics/Jv9OyS0WLNM ). Ultimately, though, this is a design decision that the Committee will have to consider. We feel that using an existing API is the better choice, but if the committee decides otherwise then we will need to adjust our approach accordingly.
 
-Mike

Michael McLaughlin

unread,
Jan 21, 2014, 1:29:45 PM1/21/14
to grap...@isocpp.org
My current thinking about this proposal is "well at least there is now a starting point".
Here are some remarks/questions:

1. About "Usage of Shared Ownership Semantics":
Did you explore the additional possibility of just not implying any kind of copy or sharing semantic at all for these types?
Taking your example:

X x1;
auto x2 = x1; // compilation error: copy is forbidden

Thus letting the user to define when, where and how to share these objects if at any moment it is proven necessary?
I suspect that hiding the sharing without providing a separate type for sharing (like future/shared_future) might give the wrong assumptions to user, 
like that he can use these objects from different threads safely with minimal issues.
I feel that if sharing of some of these objects is necessary, it should be the user that setup the sharing mechanism specific to his/her use case and constraints.

That being said, that's just a feeling so I'm wondering.

 
I think what you are describing is reference semantics. We do discuss that. The decision to go with shared ownership semantics was the most contentious design decision. The final decision was to stick with shared ownership semantics for the initial publication but to fully expect a vigorous discussion on the topic when we present it in Issaquah. I like shared ownership semantics here and will do my best to make the case that they are the best choice, but I will not be surprised if the consensus is for reference semantics instead. The only thing that would surprise me would be a decision for value semantics because of the problems discussed in the proposal.
 
 
2. I do agree that starting with Cairo provide a necessary starting point. I do not agree that the current proposal is complete or good enough to 
fill the need. One thing that highly bother me is that the result of the mechanical transformation really lack any use of C++ idioms, which 
are historically avoided by most graphic apis except the ones from very recent frameworks.
Basically, I feel that from this proposal, there is a need for a lot of manual modifications to match something useful for C++ programmers.
This is not an argument though, I'm still looking at the details to see why I don't feel comfortable with the result of the transformation in details.

 
I agree that it is not complete. We wanted feedback from the Committee on various issues before we proceeded to add rules that would make more radical changes.
 

3. Am I correct that in the current state of this proposal, the user can draw something in a surface, but can't do anything with that surface afterward?
The only thing I see is "write to png" function but there is no way to access the raw data to exploit the surface content.
Maybe something like write_to_buffer() would help? or provide direct access like a vector.data()?

 
You found a bug. Cairo has two functions - cairo_surface_map_to_image and cairo_surface_unmap_image - which should have equivalents in the library but which I overlooked. They will be added.
 
That said, if it is an image_surface, you can access its data using image_surface::get_data and image_surface::set_data. If it is not an image_surface, you can use image_surface(surface&, format, int, int) to create an image surface that matches the surface as closely as possible, create a context for the new image_surface you just created, and then draw the original surface to the new image_surface. The better approach though would be to use image_surface objects from the outset to compose various components of your scene, and then draw them to the display surface using context::set_source_surface, defining a suitable clip region, and then calling context::paint (or using set_source_surface, creating a new path, calling context::rectangle with the appropriate values, then calling context::fill). There are various other ways to do it as well.
 
In general, directly manipulating a surface's data using CPU-side functions is a really bad idea from a performance point of view. GPUs are massively parallel and bringing them to a halt so that you can start messing with data they own (and the GPU does indeed own the texture data) is going to provide a big perf hit.
 

4. That pose the question of the basic units used in Cairo. I see int double etc. but no definition of what is a pixel.
I suppose that there is a lot of work to do there.

 
There's not really a lot of work to do there right now. As you said, you saw int and double. This is a simple, 2D drawing API. We don't want users to feel like they need to know or care about what the underlying GPU representation of pixel data is. If you need to drop down to that level of detail, you are probably in the land of platform-specific information and thus in the realm of native handles.
 
That said, cairo does have a concept of a pixel (in that you can create an image_surface from data, get image surface data, etc.). The "format" enum specifies the pixel formats. See the cairo documentation for cairo_format_t for the meanings of those enumerators.
 

5. I suggest removing "user data", or is there a reason to keep it?

 
I won't be surprised if it goes away, but we didn't eliminate it yet because we wanted to be conservative and it's possible that someone will make a good case for preserving it.
 
-Mike
 

Alex B

unread,
Jan 21, 2014, 1:53:26 PM1/21/14
to grap...@isocpp.org
1. About "Usage of Shared Ownership Semantics":
Did you explore the additional possibility of just not implying any kind of copy or sharing semantic at all for these types?
Taking your example:

X x1;
auto x2 = x1; // compilation error: copy is forbidden

Thus letting the user to define when, where and how to share these objects if at any moment it is proven necessary?
I suspect that hiding the sharing without providing a separate type for sharing (like future/shared_future) might give the wrong assumptions to user, 
like that he can use these objects from different threads safely with minimal issues.
I feel that if sharing of some of these objects is necessary, it should be the user that setup the sharing mechanism specific to his/her use case and constraints.

That being said, that's just a feeling so I'm wondering.

 
I think what you are describing is reference semantics. We do discuss that. The decision to go with shared ownership semantics was the most contentious design decision. The final decision was to stick with shared ownership semantics for the initial publication but to fully expect a vigorous discussion on the topic when we present it in Issaquah. I like shared ownership semantics here and will do my best to make the case that they are the best choice, but I will not be surprised if the consensus is for reference semantics instead. The only thing that would surprise me would be a decision for value semantics because of the problems discussed in the proposal.
 
I think what Joel is describing is "value semantics without copy (move only)", but yeah, that sounds like what you call "reference semantics" in your proposal. Personnaly, I find the titles in the proposal quite confusing; to me reference semantics is what you call "shared ownership semantics".
But I'm on Joel's side on this. When reading thru the alternatives in the proposal, I expected to run into what he suggests (and also what feels the best to me) but the proposal seems to suggest that this approach necessarily requires the usage of smart pointers. I don't see the need for smart pointers at all with this approach.
Modern C++ is all about going to value semantics (with and without copy), even in the standard. std::thread is a great example. Of course, there are exceptions, like std::reference_wrapper, but in that case it is pretty explicit.

Herb Sutter

unread,
Jan 21, 2014, 2:08:03 PM1/21/14
to grap...@isocpp.org

Thanks for the feedback, everyone!

 

Just to add to what Michael has said, the proposal is trying to follow the committee’s guidance from the Chicago meeting summarized in N3791, including first to “start somewhere” with a known starting point to minimize design-by-committee while getting started, and then fix/improve it iteratively as much as needed. And N3888 isn’t “finished” even as a starting point, but it’s to start getting some initial concrete committee feedback at our next meeting; even if the feedback is positive, the best case would be a list of changes to make to the proposal to iterate on in subsequent revisions for future meetings with further changes. It’s early days yet; we’re still working on getting started.

 

But perhaps most importantly, let me emphasize the two major ways to participate: by giving feedback to help shape and refine existing proposals like N3888, and/or by writing your own competing proposal if you feel a major change or different direction is needed – both are welcome and encouraged.

 

In WG21 and similar groups, we frequently quote the saying: “Nothing in ISO happens without a proposal.” The committee can’t consider/evaluate general ideas, only actual concrete proposals. So in addition to giving feedback to improve this particular proposal, I would explicitly like to encourage anyone who thinks they know of a different/better approach to write a similar proposal to show their approach in a similar level of detail so we can consider them side by side. Disclaimer: I realize that this is asking for serious work – as with Michael’s proposal, you should realize that developing such a proposal will probably take at least person-weeks of time to come up with initial version to start discussion, with no guarantee that the committee will ever like it, and ultimately at least person-months if eventually successful. Also, it is formally optional but pragmatically highly desirable to support even an initial proposal with a working reference implementation that can be tried and inspected, as I’m glad to see Michael is working on producing.

 

We value feedback to refine existing proposals, and we’d love to see new and different proposals too. If you are serious about writing an alternative proposal of your own, ping me privately and I’ll be glad to try to offer helpful guidance as I did with Michael. Thanks,

 

Herb

 

Alex B

unread,
Jan 21, 2014, 2:10:38 PM1/21/14
to grap...@isocpp.org
 
2. I do agree that starting with Cairo provide a necessary starting point. I do not agree that the current proposal is complete or good enough to 
fill the need. One thing that highly bother me is that the result of the mechanical transformation really lack any use of C++ idioms, which 
are historically avoided by most graphic apis except the ones from very recent frameworks.
Basically, I feel that from this proposal, there is a need for a lot of manual modifications to match something useful for C++ programmers.
This is not an argument though, I'm still looking at the details to see why I don't feel comfortable with the result of the transformation in details.

 
I agree that it is not complete. We wanted feedback from the Committee on various issues before we proceeded to add rules that would make more radical changes.
 
I think that it would help to give feedback on the main issues if several small issues get fixed first. Here are some tidbits that annoyed me when reading thru quickly.
 
------
 
struct rectangle_list {
  status status;
  ::std::vector<rectangle> rectangles;
};
 
Is this struct really needed? It seems it is used as a function return type. Shouldn't the status be returned via an exception instead of a struct member?
 
------
 
union path_data
{
  struct {
    path_data_type type;
    int length;
  } header;
  struct {
    double x;
    double y;
  } point;
};
 
struct path {
  ::std::vector<path_data> data;
};
 
Please no unions... Also, no need for length in the header (the vector has it).
This could simply be:
struct point {
  double x;
  double y;
};
struct path {
  path_data_type type;
  ::std::vector<point> points;
};
 
------
 
struct matrix {
  ...
  void init(double xx, double yx, double xy, double yy, double x0, double y0); // 1
  void init_identity(); // 2
  void init_translate(double tx, double ty); // 3
  void init_scale(double sx, double sy); // 3
  void init_rotate(double radians); // 3
  ...
  static matrix multiply(const matrix& a, const matrix& b); // 4
  ...
  void transform_distance(double& dx, double& dy); // 5
  void transform_point(double& x, double& y); // 5
 
1- This function should not be needed since we have aggregate initialization.
matrix a { 2.0, 0.0, 0.0, 2.0, 0.0, 0.0 };
a = { 3.0, 0.0, 0.0, 3.0, 0.0, 0.0 };
 
2- Why not just provide a global constant representing identity?
constexpr matrix identity_matrix { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }; // <-- part of the API
a = identity_matrix; // usage example
Or make the default constructor initialize as identity.
matrix a; // a is identity
f(matrix{}); // passing identity to f
3- The problem I have with this kind of function is that you first have to declare the object (with its values initialized to something) before calling its init_something function. So values are initialized twice... Instead, there could be a make_something function.
matrix make_translation_matrix(double tx, double ty) { return {0.0, 0.0, 0.0, 0.0, tx, ty}; }
4- Please provide operator* overload instead.
5- I would much rather see an interface like this:
distance transform(const distance& d);
point transform(const point& p);
Sometimes, things are returned as a return value (like context::copy_clip_rectangle_list) and sometimes as an extra reference parameter (like region::get_extents). Everything should be consistent. Return values should be made widespread so it doesn't force a 2 phase initialization.
 
------
 
struct region {
  ...
  void intersect_region(const region& other);
  void intersect_rectangle(const rectangle_int& rectangle);
 
Should simply be named:
  void intersect(const region& other);
  void intersect(const rectangle_int& rectangle);
(there are several other cases like this one, particularily in the region class)
 
------
 
struct region {
  ...
 
Please use 'class' and not 'struct' for non-pod types.
 
------
 
struct device {
  ...
  void acquire();
  void release();
 
It would be interesing to have an utility class like 'acquire_guard' that would be RAII based, similar to std::lock_guard.
{
  device.acquire();
  ...
  device_release();
}

could become:
{
  acquire_guard<device> ag(device);
  ...
}

It would make it both convenient and exception-safe.
 
------
 
struct context {
  ...
  void line_to(double x, double y);
  void rel_line_to(double x, double y);
  void rectangle(double x, double y, double width, double height);
  ...
 
Functions taking points, distances and rectangle should, well... just take points, distances and rectangles:
  void line_to(const point& p);
  void line_to(const distance& d);
  void rectangle(const rectangle& r); // or maybe: void draw(const rectangle& r);

Michael McLaughlin

unread,
Jan 21, 2014, 3:04:16 PM1/21/14
to grap...@isocpp.org
Some of the changes you suggested are ones that I support. As I've said before, this draft was intentionally conservative.
 
The rectangle_list type will likely disappear. As I said in some other response somewhere, error handling was kept especially conservative. If at the end of the road there are no status member functions in any of the classes I will be happy. But changing error handling now would've added several additional rules with complicated transforms. The rules are already complicated and I want people to find holes in them if any exist. So complex changes were generally avoided. Indeed the primary reason cairo_pattern_t wound up as multiple types in this draft was because there would've been constructors for different pattern types that would've had the same signature. It made more sense to split the type (as that seemed an inevitable outcome) than to mess with the constructor signatures by adding meaningless parameters to differentiate them.
 
I expect matrix to change a lot.
 
I dislike the acquire and release functions of device (in fact I'm not sure that device should exist at all; the function should probably just return a native handle).
 
I opted to stick with double values rather than define types; I expect that to change. Those rules should be simple and adding them later after the initial set of rules has been evaluated and poked will, I think, provide for better results.
 
The context::rectangle function adds a rectangle to the current path, it doesn't draw anything.
 
The union is there because it's a union in cairo and there was no good reason to change that just now. Indeed it actually makes sense as a union.
 
The length part of header in path_data is not provided by the vector in path. The path vector is made up of path data elements. The first element is a path_data that is a header. This is followed by zero or more points depending on the value of type in the header (it's only zero if it's the end of the path, otherwise it's a variable number). Unless it's an empty path, the second element will be a point. How many points follow the header element is what is encoded in length. Until the type is path_data_type::close_path, the pattern continues to be header followed by a variable number of points followed by a header followed by... . The other path_data_type enumerators are move_to, line_to, and curve_to, which respectively have 1 point, 1 point, and 3 points. Since these are known quantities, the length could have been eliminated for that reason. But again, the idea was a conservative transformation to keep the rules as simple as possible to make it easy to find problems with them (if any). In fact I had eliminated length for quite some time in the implementation and was using an implementation detail function that returned the length for a provided path_data_type. I excised this to make the code match the rules.
 
I do plan to modify it so that things that are returned by reference parameter will instead be returned directly wherever possible; again this would've complicated the rules a lot.
 
I used struct for non-PODs in the Technical Specification because that is the style that the Standard uses. I'd much prefer to use class given that that is what the header in the implementation uses for those types. But I stuck to the style of the Standard as best I could because that's what the Committee will expect to see.
 
-Mike
 


Michael B. McLaughlin
Visual C++ MVP
Proprietor - Bob Taco Industries
- or -


--
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/.

Klaim - Joël Lamotte

unread,
Jan 21, 2014, 3:50:33 PM1/21/14
to grap...@isocpp.org

On Tue, Jan 21, 2014 at 12:14 AM, Michael McLaughlin <mike...@gmail.com> wrote:
You can access it here: http://isocpp.org/blog/2014/01/n3888 .

It seems that the link have changed very recently, it is now http://isocpp.org/files/papers/N3888.pdf

Alex B

unread,
Jan 21, 2014, 3:51:54 PM1/21/14
to grap...@isocpp.org
Thanks for you answer.
 
I used struct for non-PODs in the Technical Specification because that is the style that the Standard uses. I'd much prefer to use class given that that is what the header in the implementation uses for those types. But I stuck to the style of the Standard as best I could because that's what the Committee will expect to see.

I'm not sure I understand. Looking at the standard, there are plenty of types defined with the 'class' keyword (take std::thread for example).
If I remember correctly, the standard needs to specify whether it is implemented as a class or a struct because when you derive from the type, you need to declare the new type as class if deriving from class, and struct if deriving from struct. But I might be wrong about this.

Herb Sutter

unread,
Jan 21, 2014, 4:01:50 PM1/21/14
to grap...@isocpp.org

Hi Alex, “struct” and “class” have identical meaning for these purposes, and only change the default accessibility of bases and members. It’s a stylistic convention that “struct” be used for aggregates, but only a convention.

 

Herb

 

 

--

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/.

Ville Voutilainen

unread,
Jan 21, 2014, 4:04:27 PM1/21/14
to grap...@isocpp.org
On 21 January 2014 22:51, Alex B <deva...@gmail.com> wrote:
>> I used struct for non-PODs in the Technical Specification because that is
>> the style that the Standard uses. I'd much prefer to use class given that
>> that is what the header in the implementation uses for those types. But I
>> stuck to the style of the Standard as best I could because that's what the
>> Committee will expect to see.
> I'm not sure I understand. Looking at the standard, there are plenty of
> types defined with the 'class' keyword (take std::thread for example).

For types that have no invariants (like std::pair), the standard uses struct
instead of class.

> If I remember correctly, the standard needs to specify whether it is
> implemented as a class or a struct because when you derive from the type,
> you need to declare the new type as class if deriving from class, and struct
> if deriving from struct. But I might be wrong about this.


No, that's not correct at all - you can derive structs from classes and vice
versa, and the only difference between a struct and a class is the
default access.

Klaim - Joël Lamotte

unread,
Jan 21, 2014, 4:14:36 PM1/21/14
to grap...@isocpp.org
On Tue, Jan 21, 2014 at 7:29 PM, Michael McLaughlin <mike...@gmail.com> wrote:

I think what you are describing is reference semantics. We do discuss that.

Yes and no.
The reference semantic you are discussing assumes that the api will impose the use of smart pointers
to maintain a shared reference semantic. 
What I am asking, exactly, is what about move-only types and no assumption about these types being shared at all?
The difference is that depending on the use chase, there would be, or not, use of sharing constructs, where needed, and specific
to the actual need (for example, one could use a shared pointer that don't have thread safety on copy because the code
manipulating the drawing api will only be running on a specific thread anyway, or other cases that might be unusual).

Said another way: does the sharing-or-not-sharing really have to be part of this api?
 
The decision to go with shared ownership semantics was the most contentious design decision. The final decision was to stick with shared ownership semantics for the initial publication but to fully expect a vigorous discussion on the topic when we present it in Issaquah. I like shared ownership semantics here and will do my best to make the case that they are the best choice, but I will not be surprised if the consensus is for reference semantics instead. The only thing that would surprise me would be a decision for value semantics because of the problems discussed in the proposal.
 

I'm not against shared ownership semantic but I am wondering if it's not a potential issue both in performance and design,
where the library is designed for a use case but becomes expensive in another, simply because the sharing costs the same for everyone.
A bit like if we only had boost::shared_ptr smart pointers, no scoped_ptr, no unique_ptr and no other kind of pointers. It don't really fit all the usages.
So do we actually need to pre-define and force the sharing semantic and it's implementation?

It's a real question, I mean I don't know the answer at all, in the same way I might have not thought about having shared_future if I was designing the future api.
 

3. Am I correct that in the current state of this proposal, the user can draw something in a surface, but can't do anything with that surface afterward?
The only thing I see is "write to png" function but there is no way to access the raw data to exploit the surface content.
Maybe something like write_to_buffer() would help? or provide direct access like a vector.data()?

 
You found a bug. Cairo has two functions - cairo_surface_map_to_image and cairo_surface_unmap_image - which should have equivalents in the library but which I overlooked. They will be added.
 
That said, if it is an image_surface, you can access its data using image_surface::get_data and image_surface::set_data. If it is not an image_surface, you can use image_surface(surface&, format, int, int) to create an image surface that matches the surface as closely as possible, create a context for the new image_surface you just created, and then draw the original surface to the new image_surface. The better approach though would be to use image_surface objects from the outset to compose various components of your scene, and then draw them to the display surface using context::set_source_surface, defining a suitable clip region, and then calling context::paint (or using set_source_surface, creating a new path, calling context::rectangle with the appropriate values, then calling context::fill). There are various other ways to do it as well.

In general, I was thinking about the systems that will have to actually use the surface. For image_surface, it's ok, it's basically a buffer in the memory accessible to the cpu.
For surface itself, it's less simple. How should a windowing api use a surface?
If my understanding is correct, a windowing api would provide a surface child type or something equivalent, which knows how to report the drawing in the windows.
Is the the way you were imagining the usage?
 
 
In general, directly manipulating a surface's data using CPU-side functions is a really bad idea from a performance point of view. GPUs are massively parallel and bringing them to a halt so that you can start messing with data they own (and the GPU does indeed own the texture data) is going to provide a big perf hit.
 

I know about that, but if you want to go in the general case, then we'll explicitely have to separate textures where they are displayed (mesh, screen, memory?), which is why I'm asking
how would other system use the surface.
 

4. That pose the question of the basic units used in Cairo. I see int double etc. but no definition of what is a pixel.
I suppose that there is a lot of work to do there.

 
There's not really a lot of work to do there right now. As you said, you saw int and double. This is a simple, 2D drawing API. We don't want users to feel like they need to know or care about what the underlying GPU representation of pixel data is. If you need to drop down to that level of detail, you are probably in the land of platform-specific information and thus in the realm of native handles.
 

I strongly disagree.
1. these types are not telling me anything, what is the unit, can I really do all the operations an int can do on that unit without getting unusable values, etc.
2. here I have strictly no idea what is a pixel. Is it rgb? cmjn? What's the range of valid values, is it [0,1) ? [0,1]? [0,255]? 
3. as discussed in another older thread, I see no reason to not use C++14 features that allow us to benefit from types without having any cost at runtime.

I guess this part alone would require one or several proposals to get the discussion somewhere.
 
That said, cairo does have a concept of a pixel (in that you can create an image_surface from data, get image surface data, etc.). The "format" enum specifies the pixel formats. See the cairo documentation for cairo_format_t for the meanings of those enumerators.

Could you clarify if the goal  is to have an api to draw anything on any kind of surface, or should it be specialized for surfaces immediately visible on a screen and using formats destined to be displayed on that screen?
 
Alex B beat me on the api analysis! :)

Herb Sutter

unread,
Jan 21, 2014, 4:35:04 PM1/21/14
to grap...@isocpp.org

One of the options we have been discussing is move-only types, and I think they may well turn out to be the right fit here.

 

Meta: That detail in particular during this exercise has made me really appreciate how much stronger C++11 is in expressing important semantics we couldn’t express directly in C++98 (auto_ptr, anyone?), including for the purpose of wrapping lower-level APIs.

 

Herb

 

 

From: Klaim - Joël Lamotte [mailto:mjk...@gmail.com]
Sent: Tuesday, January 21, 2014 1:15 PM
To: grap...@isocpp.org
Subject: Re: [graphics] Re: N3888 - A Proposal to Add 2D Graphics Rendering and Display to C++

 

 

 

On Tue, Jan 21, 2014 at 7:29 PM, Michael McLaughlin <mike...@gmail.com> wrote:

--

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/.

John Cuyle

unread,
Jan 21, 2014, 6:34:59 PM1/21/14
to grap...@isocpp.org

I apologize in advance if this is a stupid question, but what sort of licensing issues might this run into?  I started to read over the proposal and realized that it would be beneficial to read up on cairo itself.  Cairo appears to be licensed under the LGPL or the MPL.  As a mechanical transformation, what sort of license would the proposed library have?  Would it be considered a derivative work and also be licensed under the LGPL?  If one were to do, say, a custom Direct2D/DirectWrite implementation of the new API, would it be considered a derivative and required to be open sourced?  Is it possible for someone to understand and use this library without any exposure to cairo?  Perhaps I’m just being paranoid here, but, you know, software license terms are something I take seriously and want to avoid even the slightest possibility of violating.

 

One advantage of a completely new API:  this sort of question can be avoided entirely.

 

From: Michael McLaughlin [mailto:mike...@gmail.com]
Sent: Tuesday, January 21, 2014 9:11 AM
To: grap...@isocpp.org
Subject: Re: [graphics] Re: N3888 - A Proposal to Add 2D Graphics Rendering and Display to C++

 

This is one of the kinds of feedback that I was hoping for. You've identified a weakness in our Design Decisions sections. When I wrote the part discussing synthesizing a new API, I was unconsciously relying on the reader to be familiar with N3791 - http://isocpp.org/files/papers/n3791.html . This was a mistake on my part and it should have been explicitly cited there and perhaps even briefly summarized. I am not sure if we will publish an update pre-conference (I need to consult my co-authors), but I am going to modify that section to try to address your feedback. So thank you!

Michael McLaughlin

unread,
Jan 21, 2014, 6:36:06 PM1/21/14
to grap...@isocpp.org

I think what you are describing is reference semantics. We do discuss that.

Yes and no.
The reference semantic you are discussing assumes that the api will impose the use of smart pointers
to maintain a shared reference semantic. 
What I am asking, exactly, is what about move-only types and no assumption about these types being shared at all?
The difference is that depending on the use chase, there would be, or not, use of sharing constructs, where needed, and specific
to the actual need (for example, one could use a shared pointer that don't have thread safety on copy because the code
manipulating the drawing api will only be running on a specific thread anyway, or other cases that might be unusual).
 
To create a context it needs a surface. There are other valid reasons to have access to that surface (e.g. to use it as the source of a surface_pattern that you then draw with using a different context). Move-only types instantly force the API to deal with surfaces through shared_ptr, since otherwise you give up a whole bunch of use cases (in the example above, the first context and the pattern both need to retain that surface; the only solutions I know of to do that are a (horribly dangerous) naked pointer, a shared_ptr, or by giving the surface class shared ownership semantics).
 
I like shared_ptr. I like that it exists. I like that it's there when needed. I don't like the idea of an API that's littered with shared_ptr parameters because types which should natively have shared ownership semantics instead have move only semantics. Especially since if you mess up with shared_ptr you wind up with a resource that destroys itself while you still think there are outstanding references to it. Shared ownership semantics let you have the nice clean look and feel of value semantics without wasting memory and computing cycles on deep copying GPU resources for no reason and without the risk of early destruction. Yes, patterns that create early destruction are invalid but I see no reason why a beginning programmer should have to try to debug a runtime error that could've been avoided by the library designer.
 

Said another way: does the sharing-or-not-sharing really have to be part of this api?
 
The decision to go with shared ownership semantics was the most contentious design decision. The final decision was to stick with shared ownership semantics for the initial publication but to fully expect a vigorous discussion on the topic when we present it in Issaquah. I like shared ownership semantics here and will do my best to make the case that they are the best choice, but I will not be surprised if the consensus is for reference semantics instead. The only thing that would surprise me would be a decision for value semantics because of the problems discussed in the proposal.
 

I'm not against shared ownership semantic but I am wondering if it's not a potential issue both in performance and design,
where the library is designed for a use case but becomes expensive in another, simply because the sharing costs the same for everyone.
A bit like if we only had boost::shared_ptr smart pointers, no scoped_ptr, no unique_ptr and no other kind of pointers. It don't really fit all the usages.
So do we actually need to pre-define and force the sharing semantic and it's implementation?

It's a real question, I mean I don't know the answer at all, in the same way I might have not thought about having shared_future if I was designing the future api.
 
How is it a performance and design issue? Please describe the use cases where this is a problem. I really want to know because I can't think of any so if there are any I want to be able to address them if possible, and recommend an alternate design if not.
 

 

3. Am I correct that in the current state of this proposal, the user can draw something in a surface, but can't do anything with that surface afterward?
The only thing I see is "write to png" function but there is no way to access the raw data to exploit the surface content.
Maybe something like write_to_buffer() would help? or provide direct access like a vector.data()?

 
You found a bug. Cairo has two functions - cairo_surface_map_to_image and cairo_surface_unmap_image - which should have equivalents in the library but which I overlooked. They will be added.
 
That said, if it is an image_surface, you can access its data using image_surface::get_data and image_surface::set_data. If it is not an image_surface, you can use image_surface(surface&, format, int, int) to create an image surface that matches the surface as closely as possible, create a context for the new image_surface you just created, and then draw the original surface to the new image_surface. The better approach though would be to use image_surface objects from the outset to compose various components of your scene, and then draw them to the display surface using context::set_source_surface, defining a suitable clip region, and then calling context::paint (or using set_source_surface, creating a new path, calling context::rectangle with the appropriate values, then calling context::fill). There are various other ways to do it as well.

In general, I was thinking about the systems that will have to actually use the surface. For image_surface, it's ok, it's basically a buffer in the memory accessible to the cpu.
For surface itself, it's less simple. How should a windowing api use a surface?
If my understanding is correct, a windowing api would provide a surface child type or something equivalent, which knows how to report the drawing in the windows.
Is the the way you were imagining the usage?
 
 
Cairo deals with this with a variety of backends. As does Qt. You seem to be asking me how some generic backend should handle some implementation detail, if I'm understanding you correctly. The answer is that implementations should handle implementation details in the best, most efficient way possible. I am not concerned about the implementation details so long as I know that the things in question are in fact implementable with acceptable performance (I do thanks to cairo, Qt, and other libraries).
 

 
In general, directly manipulating a surface's data using CPU-side functions is a really bad idea from a performance point of view. GPUs are massively parallel and bringing them to a halt so that you can start messing with data they own (and the GPU does indeed own the texture data) is going to provide a big perf hit.
 

I know about that, but if you want to go in the general case, then we'll explicitely have to separate textures where they are displayed (mesh, screen, memory?), which is why I'm asking
how would other system use the surface.
 
 
I'm sorry but I don't understand what you are asking here. But again it sounds like an implementation detail question and while implementation details are not ignorable since an API that cannot be implemented in a useful way does nobody (except theorists) any good, neither are they of any concern once it's known that the API can be usefully implemented. The existence of cairo attests to this fact, ergo I have not spent time thinking about how various windowing systems might hypothetically implement the API. There are people out there who get paid lots of money to think about that. I am a volunteer. If someone wants to pay me lots of money to think about such things I would be more than happy to hear from them.
 
 

4. That pose the question of the basic units used in Cairo. I see int double etc. but no definition of what is a pixel.
I suppose that there is a lot of work to do there.

 
There's not really a lot of work to do there right now. As you said, you saw int and double. This is a simple, 2D drawing API. We don't want users to feel like they need to know or care about what the underlying GPU representation of pixel data is. If you need to drop down to that level of detail, you are probably in the land of platform-specific information and thus in the realm of native handles.
 

I strongly disagree.
1. these types are not telling me anything, what is the unit, can I really do all the operations an int can do on that unit without getting unusable values, etc.
2. here I have strictly no idea what is a pixel. Is it rgb? cmjn? What's the range of valid values, is it [0,1) ? [0,1]? [0,255]? 
3. as discussed in another older thread, I see no reason to not use C++14 features that allow us to benefit from types without having any cost at runtime.

I guess this part alone would require one or several proposals to get the discussion somewhere.
 
You are asking questions that are all answered by the cairo API documentation. I told you this in my last reply. You even quoted the sentence where I explain this (just below here). And the proposal states that the semantics are as defined by the cairo API documentation.
 
Image surface formats: http://cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t . Values for the solid_color_pattern constructors: http://cairographics.org/manual/cairo-cairo-pattern-t.html#cairo-pattern-create-rgba . I'm sorry but I do not want to waste everyone's time pasting links to every last bit of relevant cairo documentation so you'll need to look this stuff up yourself.
 
The answer to why there aren't UDLs is the same as the answer I repeatedly gave to Alex's questions: every addition or modification requires one or more additional rules. There are already 7.5 pages of rules. Bonus features like UDLs can come later after the existing rules have been vetted.
 

 
That said, cairo does have a concept of a pixel (in that you can create an image_surface from data, get image surface data, etc.). The "format" enum specifies the pixel formats. See the cairo documentation for cairo_format_t for the meanings of those enumerators.

Could you clarify if the goal  is to have an api to draw anything on any kind of surface, or should it be specialized for surfaces immediately visible on a screen and using formats destined to be displayed on that screen?
 
You already know the answer to this. You acknowledged it above when you described image_surface. The goals of this API are as stated in the proposal's introduction and motivation and scope sections. There is also further background material about the goals in N3791, linked to in the References section.
 
-Mike

Michael McLaughlin

unread,
Jan 21, 2014, 7:00:17 PM1/21/14
to grap...@isocpp.org
This is not a stupid question. I am a (retired) lawyer and take licensing quite seriously as well. Please note that nothing I am writing, have written, or will write should be considered legal advice and I urge anyone with any legal questions to discuss them with a knowledgeable attorney.
 
To start with, the cairo maintainers have all seemed favorable to this project. That's not an answer to the licensing question, but if they hadn't been agreeable we would not have gone against their wishes. Herb is better suited to answer this than I am since he is more familiar with ISO's IP licensing policies. Cairo can be licensed under the LGPL or the MPL 1.1. The LGPL is likely unsatisfactory for various reasons. Since cairo gives the licensee the choice, it is contemplated that anything that would need to be licensed would be licensed under the MPL. A request for clarification of what this would mean has been sent to the appropriate people at the ISO secretariat. A reply has not yet been received.
 
Because I am a retired lawyer I cannot disclose my own opinion about this issue without violating the Laws and Regulations of the State of New York. All I feel comfortable saying is that if I anticipated any long term issues arising from the interaction between the MPL and the use of cairo in creating this proposal, I would not have spent time creating the proposal (please note that I am not infallible). Ultimately it comes down to the what the ISO folks say. Hopefully Herb will have a chance to comment on how IP licensing generally works with ISO.
 
-Mike
 


Michael B. McLaughlin
Visual C++ MVP
Proprietor - Bob Taco Industries
- or -


Alex B

unread,
Jan 21, 2014, 7:40:37 PM1/21/14
to grap...@isocpp.org
On Tue, Jan 21, 2014 at 4:04 PM, Ville Voutilainen <ville.vo...@gmail.com> wrote:

No, that's not correct at all - you can derive structs from classes and vice
versa, and the only difference between a struct and a class is the
default access.
 
My mistake. I remember a compiler reporting a warning when deriving struct from class. That was a few year ago; it's probably fixed (I don't remember which compiler it was...) 

Klaim - Joël Lamotte

unread,
Jan 21, 2014, 7:56:47 PM1/21/14
to grap...@isocpp.org
On Wed, Jan 22, 2014 at 12:36 AM, Michael McLaughlin <mike...@gmail.com> wrote:

To create a context it needs a surface. There are other valid reasons to have access to that surface (e.g. to use it as the source of a surface_pattern that you then draw with using a different context). Move-only types instantly force the API to deal with surfaces through shared_ptr, since otherwise you give up a whole bunch of use cases (in the example above, the first context and the pattern both need to retain that surface; the only solutions I know of to do that are a (horribly dangerous) naked pointer, a shared_ptr, or by giving the surface class shared ownership semantics).
 

I disagree with the last sentence but I agree it's easy to deduce the need for smart pointer, which is not what I was suggesting.
 
I like shared_ptr. I like that it exists. I like that it's there when needed. I don't like the idea of an API that's littered with shared_ptr parameters because types which should natively have shared ownership semantics instead have move only semantics. Especially since if you mess up with shared_ptr you wind up with a resource that destroys itself while you still think there are outstanding references to it. Shared ownership semantics let you have the nice clean look and feel of value semantics without wasting memory and computing cycles on deep copying GPU resources for no reason and without the risk of early destruction. Yes, patterns that create early destruction are invalid but I see no reason why a beginning programmer should have to try to debug a runtime error that could've been avoided by the library designer.
 

You are arguing against having shared_ptr in the API and I agree it would not be good. 
What I am not convinced about is to inforce any kind of sharing semantic at all into the api, maybe it's better to let the user decide what to do with the constructs.
[I think we need a test case to discuss this, I'll try to produce one so that I'm clear.]
Just in case that helps understanding what I'm asking, 

    surface s  = some_system.new_surface();
    context c { s }; 
    
Here, using shared ownership, c own s, which also mean that s will not be destroyed if c is still alive, even if s have been provided by another system.
With the same usage syntax, using move-only types with no implied shared ownership, this code would work the same, but c would hold a reference to s and would go undefined behaviour
if s is destroyed before c and c is still used.
Then IFF s needs to be shared, the user can use any sharing construct he/she wants, which can something else than smart pointers if ownership is not wanted.

This is basically how std::thread works if you prefer.

I'm sorry I might not be totally clear, but I'll look for typical examples to clarify my points.


I'm not against shared ownership semantic but I am wondering if it's not a potential issue both in performance and design,
where the library is designed for a use case but becomes expensive in another, simply because the sharing costs the same for everyone.
A bit like if we only had boost::shared_ptr smart pointers, no scoped_ptr, no unique_ptr and no other kind of pointers. It don't really fit all the usages.
So do we actually need to pre-define and force the sharing semantic and it's implementation?

It's a real question, I mean I don't know the answer at all, in the same way I might have not thought about having shared_future if I was designing the future api.
 
How is it a performance and design issue? Please describe the use cases where this is a problem. I really want to know because I can't think of any so if there are any I want to be able to address them if possible, and recommend an alternate design if not.
 

I'm not saying that there IS per se a performance and design issue, I said "I am wondering if it's a potential issue" because of potential rigidity of the api (which might not be a problem in practice).
If the ownership semantic is *pre-defined*, it have to be good (and efficient) for all use cases, so I am questionning if it's a good idea to force that shared ownership instead of letting the user choose how and when to share anything, if necessary.
If it's indeed unavoidable (but so far I'm not convinced), then it would make clear why shared ownership semantic is necessary.
  
Cairo deals with this with a variety of backends. As does Qt. You seem to be asking me how some generic backend should handle some implementation detail, if I'm understanding you correctly. The answer is that implementations should handle implementation details in the best, most efficient way possible. I am not concerned about the implementation details so long as I know that the things in question are in fact implementable with acceptable performance (I do thanks to cairo, Qt, and other libraries).
 
...

 
I'm sorry but I don't understand what you are asking here. But again it sounds like an implementation detail question and while implementation details are not ignorable since an API that cannot be implemented in a useful way does nobody (except theorists) any good, neither are they of any concern once it's known that the API can be usefully implemented. The existence of cairo attests to this fact, ergo I have not spent time thinking about how various windowing systems might hypothetically implement the API. There are people out there who get paid lots of money to think about that. I am a volunteer. If someone wants to pay me lots of money to think about such things I would be more than happy to hear from them.

I was not asking for implementation details but about how a surface will be used by the person who does the implementation details, like a windowing system.
I was actually confused by a misconception about the surface type.
I understand now that surface is actually an abstract type, from which specific implementations would be derived from; it was not totally clear to me before.

I strongly disagree.
1. these types are not telling me anything, what is the unit, can I really do all the operations an int can do on that unit without getting unusable values, etc.
2. here I have strictly no idea what is a pixel. Is it rgb? cmjn? What's the range of valid values, is it [0,1) ? [0,1]? [0,255]? 
3. as discussed in another older thread, I see no reason to not use C++14 features that allow us to benefit from types without having any cost at runtime.

I guess this part alone would require one or several proposals to get the discussion somewhere.
 
You are asking questions that are all answered by the cairo API documentation. I told you this in my last reply. You even quoted the sentence where I explain this (just below here). And the proposal states that the semantics are as defined by the cairo API documentation.
 
Image surface formats: http://cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t . Values for the solid_color_pattern constructors: http://cairographics.org/manual/cairo-cairo-pattern-t.html#cairo-pattern-create-rgba . I'm sorry but I do not want to waste everyone's time pasting links to every last bit of relevant cairo documentation so you'll need to look this stuff up yourself.
 

Let me rephrase my question: why aren't these information visible in the manipulated types, for example here:

    // in the context struct
    void set_source_rgb(double red, double green, double blue);

This is exaclty the kind of api that, for example, std::chrono makes impossible to get wrong.
This is also typical of C code and graphics api which don't want to deal too much with C++ type sytem.
I am saying I disagree with this kind of design. This have nothing to do with cairo_format_t and related enums (which shouldn't be enums by the way, but at least enum classes).
 
The answer to why there aren't UDLs is the same as the answer I repeatedly gave to Alex's questions: every addition or modification requires one or more additional rules. There are already 7.5 pages of rules. Bonus features like UDLs can come later after the existing rules have been vetted.

I might have had the wrong assumption that this is a starting point from which manual changes would be necessary to get further, not that you would have to add new rules to the current document.
I don't think (but I might be wrong) that the mechanical transformation will work for all necessary modifications. I believe it will need manual editing.

 

Herb Sutter

unread,
Jan 22, 2014, 7:45:32 PM1/22/14
to grap...@isocpp.org

The only concrete answer is: We’ve asked ISO, and they will give us direction in the fullness of time. ;) I’ve asked, and it can take time to get an answer.

 

In general, virtually every standards submission involves some IP, even if it’s just the author’s implicit copyright on his own paper.

 

In particular, contributions from OSS are reasonably common and so presumably ISO is used to answering these questions.

 

For those interested in more, see also http://isocpp.org/std, which refers to:

 

For a general overview of ISO standardization, including the ISO patent and copyright policy, see ISO’s document Participating in International Standardization.

 

Herb

 

 

Michael McLaughlin

unread,
Jan 25, 2014, 3:35:52 AM1/25/14
to grap...@isocpp.org
The reference implementation is now posted to GitHub: https://github.com/mikebmcl/N3888_RefImpl . It currently requires Windows (tested on 7 and 8.1) with Visual Studio 2013 (the free Visual Studio 2013 Express for Windows Desktop works fine).
 
I'm hoping we will have a GNU/Linux X11-based (or maybe XCB-based) build using GCC sometime in the near future but I can't make any promises. (The code is mostly standard, portable C++ with only a handful of Windows-specific things, most of which relate to the entry point and creating a window. So it's almost entirely a matter of finding the time to create a project file system using CMake or Autotools. The past few days have been pretty quiet and thus productive but now with the reference implementation rolling out there could be a lot of feedback, questions, and concerns that need attention. So we'll see. It shouldn't be difficult to do a quick and dirty port if you want to try it out on a different platform).
 
Also, I can't promise there are no bugs. I've found and squashed several this week but there may be more lurking which will show up when I have a chance to really test the functionality.
 
Thanks!
 
-Mike
 
(p.s. Apologies to those who read this in multiple places since I am copying and pasting the same release message because I'm exhausted and want to get to sleep!)

Michael McLaughlin

unread,
Feb 11, 2014, 2:12:06 PM2/11/14
to grap...@isocpp.org
The near future has finally arrived. A GNU/Linux implementation (probably works on *BSDs and other UNIX variants too) using GTK+3 (3.8+ required) and cairo (1.12.16+ required) is now integrated into the master branch. There are build instructions in the root folder. I've tested it on 32-bit versions of OpenSUSE 13.1 and Ubuntu 13.10. The windowing code isn't pretty and isn't an exact behavior match to the Windows version but I did make an effort to make it close. So go forth and enjoy. If there are questions, problems, or bugs, I'll do my best to address them.
 
Please note that doing this required moving some files and renaming some directories. The Visual C++/Win32 version has been updated to deal with this. You may wind up with some "legacy" directories left behind if you already have the code and do a pull. Same GitHub url as in the original post.
  
Thanks!
 
-Mike
Reply all
Reply to author
Forward
0 new messages