I have a few specific places in my code where I use specific pixel dimensions to blit certain things to the screen. Obviously these are placed in well named constants, but I'm worried that it's still kind of vague.
Example: This is in a small function's local scope, so I would hope it's obvious that the constant's name applies to what the method name refers to.
const int X_COORD = 430.0;
const int Y_COORD = 458.0;
ApplySurface( X_COORD, Y_COORD, .... );
...
The location on the screen was calculated specifically for that spot. I almost feel as if I should be making constants that say SCREEN_BOTTOM_RIGHT so I could do like something like const int X_COORD = SCREEN_BOTTOM_RIGHT - SOME_OTHER_NAME.
Is the code above too ambiguous? Or as a developer would you see that and say, alright, thats (430, 458) on the screen. Got it.
Depends. Is there a particular reason those constants are what they are? (For instance, is that "430" actually 200 pixels to the left of some other element?)
If so, then it'd probably make more sense to express it in terms of the constant used for the other element (or whatever reason results in that number).
If they're all just arbitrary positions, then expressing them as coordinates makes sense. But chances are, they're not actually arbitrary.
What size screen are you assuming I have? People have very different screen resolutions on their machines, and any fixed pixel size or position is going to be wrong for some people some of the time. My normal display is 1900x1220; my other display is 1440x1050; other people use screens with different sizes. If you are displaying to a fixed size window that the user cannot resize, then it may be safer to use fixed sizes.
Without knowing what ApplySurface() does, it is hard to say whether it is clear as written. However, the relative names could well be sensible. As a maintenance programmer, I'd have no idea where the values 430 and 458 were derived from without a supporting comment unless you used an expression to make it clear.
Related
So I have a struct I need to create. Essentially its purpose is that an array of these structs will be returned from a variety of functions. All of these structs will be gathered (maybe a few hundred) and I will then need the normal for the least of them.
So to sort of summarise I have a situation where there will be many of these structs however the normal value will only be needed for one of them.
As such I was trying to create a struct that captures this idea. That way the one chosen struct can either contain its normal or a method to calculate it. As such I designed the following struct:
struct result {
float t;
bool calculated; // Tells whether to use result.normal.norm or result.norm.calculate()
union normal {
float2 norm;
float2 (*calculate)();
};
};
Is this the proper way to express this idea?
*For examples sake some of these normal calculations might involve some calculations like trig to figure out a normal on a complex curved surface. We would only want to calculate this if absolutely necessary.
(I don't believe you've provided enough context to fully answer your question, but I'll try based on what you've given me.)
Is this the proper way to express this idea?
Since you seem to be concerned with performance - probably not. Calling a function through a function pointer is (edit:) often expensive. What's more, that function doesn't even get the t field's value when you call it... so this will probably not even work.
What should you do, then?
First, figure out if this is even a pain point w.r.t. performance. Don't just optimize this because there's a potential for optimization.
Assuming this is useful to optimize - try avoiding this whole materialization-of-results. Instead, determine which float needs its norm, then be willing to spend some effort getting that norm; it won't be that bad since you'll only be doing work for one piece of data rather than all of them.
PS - No need to use unions these days, we have std::variant in C++17. The would save you the boolean, too.
I'm using OpenGL, and in my code I have some unreadable and annoying lines like:
newChild->dposition = dvec_4(dvec_4(newChild->boundingVerts[2].position, 1) + newChild->parent->dposition);
The idea was to keep positions in vec3s, with many objects in the scene it could amount to a good saving in storage, and even more importantly reduce the size of buffers sent to the graphics card. But it leads to really hard to read code casting back and fourth, plus all the casts I imagine do cost something. So is it better to keep vec4s to avoid the casting?
Without having access to all of the code, it is hard to say.
However, I would rather say that using vec4s might bring performance/code quality benefits:
Guessing that the data is likely used on the GPU, it is likely more efficient to load/store a vec4, than a vec3. I am not exactly sure, but I do not think that there is a single instruction to load a vec3. It will be broken into loading a vec2 and a float I think.
Later, you could easily store some additional data into that additional float.
Less casting and making code more readable.
Depending on the memory layout/member types of your struct, it might be so that the struct is aligned to 16 bytes anyway undoing your "memory optimization".
If something is wrong, please correct me.
I am interested in getting the maximum hardware-supported resolution for textures.
There are, as far as I have found, two mechanisms for doing something related to this:
glGetIntegerv(GL_MAX_TEXTURE_SIZE,&dim) for 2D (and cube?) textures has served me well. For 3D textures, I discovered (the hard way) that you need to use GL_MAX_3D_TEXTURE_SIZE instead. As far as I can tell, these return the maximum resolution along one side, with the other sides assumed to be the same.
It is unclear what these values actually represent. The values returned by glGetIntegerv(...) are to be considered "rough estimate"s, according to the documentation, but it's unclear whether they are conservative underestimates, best guesses, or best-cases. Furthermore, it's unclear whether these are hardware limitations or current limitations based on the amount of available graphics memory.
The documentation instead suggests using . . .
GL_PROXY_TEXTURE_(1|2|3)D/GL_PROXY_TEXTURE_CUBE_MAP. The idea here is you make a proxy texture before you make your real one. Then, you check to see whether the proxy texture was okay by checking the actual dimensions it got. For 3D textures, that would look like:
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &height);
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &depth);
If all goes well, then the dimensions returned will be nonzero (and presumably the same as what you requested). Then you delete the proxy and make the texture for real.
Some older sources state that proxy textures give outright wrong answers, but that may not be true today.
So, for modern OpenGL (GL 4.* is fine), what is the best way to get the maximum hardware-supported resolution for 1D-, 2D-, 3D-, and cube-textures?
There is a separate value for cube maps, which is queried with GL_MAX_CUBE_MAP_TEXTURE_SIZE. So the limits are:
GL_MAX_TEXTURE_SIZE: Maximum size for GL_TEXTURE_1D and GL_TEXTURE_2D.
GL_MAX_RECTANGLE_TEXTURE_SIZE: Maximum size for GL_TEXTURE_RECTANGLE.
GL_MAX_CUBE_MAP_TEXTURE_SIZE: Maximum size for GL_TEXTURE_CUBE_MAP.
GL_MAX_3D_TEXTURE_SIZE: Maximum size for GL_TEXTURE_3D.
The "rough estimate" language you found on the man pages seems unfortunate. If you look at the much more relevant spec document instead, it talks about the "maximum allowable width and height", or simply says that it's an error to use a size larger than these limits.
These limits represent the maximum sizes supported by the hardware. Or more precisely, the advertised hardware limit. It's of course legal for hardware to restrict the limit below what the hardware could actually support, as long as the advertised limit is consistently applied. Picture that the hardware can only manage/sample textures up to a given size, and this is the size reported by these limits.
These limits have nothing to do with the amount of memory available, so staying within these limits is absolutely no guarantee that a texture of the size can successfully be allocated.
I believe the intention of proxy textures is to let you check what size can actually be allocated. I don't know if that works reliably on any platforms. The mechanism really is not a good fit for how modern GPUs manage memory. But I have never used proxy textures, or dealt with implementing them. I would definitely expect significant platform/vendor dependencies in how exactly they operate. So you should probably try if they give you the desired results on the platforms you care about.
The values returned by glGetIntegerv() for GL_MAX_TEXTURE_SIZE annd GL_MAX_3D_TEXTURE_SIZE are the correct limits for the particular implementation.
It is unclear what these values actually represent. The values
returned by glGetIntegerv(...) are to be considered "rough estimate"s,
according to the documentation, but it's unclear whether they are
conservative underestimates, best guesses, or best-cases.
What kind of documentation are you refering to? The GL spec is very clear on the meaning of those values, and they are not estimates of any kind.
The proxy method should work, too, but does not directly allow you to query the limits. You could of use binary search to narrow down the exact limit via that proxy texture path, but that is just a rather clumsy approach.
If execution speed is important, should I use this,
struct myType {
float dim[3];
};
myType arr[size];
or to use a 2D array as arr[size][index]
It does not matter. The compiler will produce the exact same code regardless in almost all cases. The only difference would be if the struct induced some kind of padding, but given that you have floats that seems unlikely.
It depends on your use case. If you use the three dimensions typically together, the struct organization can be reasonable. Especially when using the dimension individually the array layout is most likely to give better performance: contemporary processors don't just load individual words but rather units of cache lines. If only parts of the data is used there are words loaded which aren't used.
The array layout is also more accessible to parallel processing e.g. using SIMD operations. This is unfortunate to some extend because the object layout is generally different. Actually, the arrays you are using are probably similar but if you change things to become float array[3][size] things become different.
No difference at all. Pick what is more readable to you.
Unless you're working on some weird platform, the memory layout of those two will be the same -- and for the compiler this is what counts most.
The only difference is when you pass something to a function.
When you use the array solution, you never copy the array contains but just pass the array address.
The structs will always be copied if you don't explicitly pass the struct address in case of the struct solution.
One other thing to keep in mind that another poster mentioned: If dim will always have a size of 3 in the struct, but the collection really represents something like "Red, Green, Blue" or "X, Y, Z" or "Car, Truck, Boat", from a maintenance standpoint you might be better off breaking them out. That is, use something like
typedef struct VEHICLES
{
float fCar;
float fTruck;
float fBoat;
} Vehicles;
That way when you come back in two years to debug it, or someone else has to look at it, they will not have to guess what dim[0], dim[1] and dim[2] refer to.
You might want to map out the 2d array to 1d. Might be more cache friendly
I have a class MyClass that stores a collection of PixelDescriptor* objects. MyClass uses a function specified by a Strategy pattern style object (call it DescriptorFunction) to do something for each descriptor:
void MyFunction()
{
descriptorA = DescriptorCollection[0];
for_each descriptor in DescriptorCollection
{
DescriptorFunction->DoSomething(descriptor)
}
}
However, this only makes sense if the descriptors are of a type that the DescriptorFunction knows how to handle. That is, not all DescriptorFunction's know how to handle all descriptor types, but as long as the descriptors that are stored are of the type that the visitor that is specified knows about, all is well.
How would you ensure the right type of descriptors are computed? Even worse, what if the strategy object needs more than one type of descriptor?
I was thinking about making a composite descriptor type, something like:
class CompositeDescriptor
{
std::vector<PixelDescriptor*> Descriptors;
}
Then a CompositeDescriptor could be passed to the DescriptorFunction. But again, how would I ensure that the correct descriptors are present in the CompositeDescriptor?
As a more concrete example, say one descriptor is Color and another is Intensity. One Strategy may be to average Colors. Another strategy may be to average Intensities. A third strategy may be to pick the larger of the average color or the average intensity.
I've thought about having another Strategy style class called DescriptorCreator that the client would be responsible for setting up. If a ColorDescriptorCreator was provided, then the ColorDescriptorFunction would have everything it needs. But making the client responsible for getting this pairing correct seems like a bad idea.
Any thoughts/suggestions?
EDIT: In response to Tom's comments, a bit more information:
Essentially DescriptorFunction is comparing two pixels in an image. These comparisons can be done in many ways (besides just finding the absolute difference between the pixels themseles). For example 1) Compute the average of corresponding pixels in regions around the pixels (centered at the pixels). 2) Compute a fancier "descriptor" which typically produces a vector at each pixel and average the difference of the two vectors element-wise. 3) compare 3D points corresponding to the pixel locations in external data, etc etc.
I've run into two problems.
1) I don't want to compute everything inside the strategy (if the strategy just took the 2 pixels to compare as arguments) because then the strategy has to store lots of other data (the image, there is a mask involved describing some invalid regions, etc etc) and I don't think it should be responsible for that.
2) Some of these things are expensive to compute. I have to do this millions of times (the pixels being compared are always difference, but the features at each pixel do not change), so I don't want to compute any feature more than once. For example, consider the strategy function compares the fancy descriptors. In each iteration, one pixels is compared to all other pixels. This means in the second iteration, all of the features would have to be computed again, which is extremely redundant. This data needs to be stored somewhere that all of the strategies can access it - this is why I was trying to keep a vector in the main client.
Does this clarify the problem? Thanks for the help so far!
The first part sounds like a visitor pattern could be appropriate. A visitor can ignore any types it doesn't want to handle.
If they require more than one descriptor type, then it is a different abstraction entirely. Your description is somewhat vague, so it's hard to say exactly what to do. I suspect that you are over thinking it. I say that because generally choosing arguments for an algorithm is a high level concern.
I think the best advice is to try it out.
I would write each algorithm with the concrete arguments (or stubs if its well understood). Write code to translate the collection into the concrete arguments. If there is an abstraction to be made, it should be apparent while writing your translations. Writing a few choice helper functions for these translations is usually the bulk of the work.
Giving a concrete example of the descriptors and a few example declarations might give enough information to offer more guidance.