KhronosGroup / KTX-Specification

KTX file format source
Other
70 stars 12 forks source link

Tighten dimensions restrictions #11

Closed lexaknyazev closed 5 years ago

lexaknyazev commented 5 years ago

Following existing restrictions on pixelHeight and pixelDepth, the spec should state that pixelWidth cannot be 0.

Common dimensions combinations could be organized like this:

Type pixelWidth pixelHeight pixelDepth numOfArrayElements numOfFaces
1D > 0 0 0 0 1
2D > 0 > 0 0 0 1
3D > 0 > 0 > 0 0 1
CUBE > 0 > 0 0 0 6
1D_ARRAY > 0 0 0 > 0 1
2D_ARRAY > 0 > 0 0 > 0 1
CUBE_ARRAY > 0 > 0 0 > 0 6

Any combination that doesn't fit the table above should be declared invalid and the loader should refuse to continue reading a file.

We should decide whether to allow (given that there's no API support for these):

jherico commented 5 years ago

Incomplete cubemaps are not uncommon. Lack of API support here just means undefined results from sampling the unpopulated side, right? There are instances where the client can ensure that simply never happens.

lexaknyazev commented 5 years ago

Aside from API requirements (which could be fulfilled at runtime via filling missing faces with zeros or false color), the spec lacks a way of signalling which faces are present.

Iff there's a need to support incomplete cubemaps, header needs to be changed. A simple solution is to turn numberOfFaces into a bitfield:

1 - not a cubemap
64 |  1 - +X is present
64 |  2 - -X is present
64 |  4 - +Y is present
64 |  8 - -Y is present
64 | 16 - +Z is present
64 | 32 - -Z is present
127 - complete cubemap
MarkCallow commented 5 years ago

Please submit a pull request with the proposed table.

It was previously decided that cubemaps must be complete. numberOfFaces has to be 1 or 6. We need more input and possibly a straw poll or vote to decide if incomplete cubemaps should be supported.

MarkCallow commented 5 years ago

I do not think we should support 3D arrays or cubemaps with 3D arrays.

MarkCallow commented 5 years ago

I have labelled this help wanted in the hope of attracting other comments on the cubemap question.

MarkCallow commented 5 years ago

Incomplete cubemaps are not uncommon

Please cite some examples.

jherico commented 5 years ago

Applications that know that geometry will always obscure the down direction don't need to populate the -Y cubemap face.

MarkCallow commented 5 years ago

@jherico, I was requesting pointers to some actual applications that do this so, among other things, we can see how they deal with the lack of API support.

In OpenGL sampling an incomplete cubemap results in the invalid pixel value - opaque black. As far as I can see in Vulkan also, 6 faces (layerCount = 6) is required for validity otherwise results are undefined. (It is much harder to deduce this in the Vulkan spec...) So even if a face is obscured, data must be uploaded.

The only saving of partial cubemaps then is file size or transmission time. KTX2 has supercompression which will alleviate both of these issues (assuming a constant color over the obscured face). Therefore I do not see a pressing need for partial cubemap support.

jherico commented 5 years ago

Sorry, I don't have any actual pointers to code. However, I feel like it's more reasonable to say that the onus for creating a valid GPU image is on the consumer of a KTX file. If a file contains 5 faces, and your API absolutely requires 6, then the developer needs to allocate and populate 6 faces, presumably populating the missing faces with some constant value.

The alternative is saying "You can't create a cubemap KTX file unless you're willing to provide 6 faces". Someone, somewhere is going to have to essentially fake a face, and since a buffer full of zeros is easier to construct in memory than it is to transmit over the internet, I'd rather that missing face generation happen as close to the GPU as possible.

lexaknyazev commented 5 years ago

One more cubemap restriction: pixelWidth must be equal to pixelHeight.

lexaknyazev commented 5 years ago

@MarkCallow Here's my preference on questions from the OP.

3D arrays Yes. With supercompression applied, they will be a simple way of storing volumetric data scattered across time.

Incomplete cubemaps Yes. Although supercompression will optimize transmission size, explicitly omitted faces bear more semantic value than filled with one color. Moreover, engines might have their own opinion regarding how omitted faces should be filled.

Cubemaps with 3D textures or cubemaps with 3D arrays No. I'm not aware of any use case for such layouts. Anyway, the restriction could be lifted with a minor version update (like KTX 23) if needed.

dewilkinson commented 5 years ago

My preference for structures in KTX2 (or any container format) is that we keep them API friendly as much as possible.

Given that none of the APIs allow for partial cubemaps, I’d vote to keep the complete restriction.

There’s no compression benefit during transmission for partial vs complete cubemaps. Setting unused faces to a solid color will effectively compress down to nothing in the bitstream.

darksylinc commented 5 years ago

In general, adding more dimensions adds exponential complexity.

incomplete cubemaps (numOfFaces > 1 && numOfFaces < 6);

Incomplete cubemaps are nothing more than 2D arrays with numOfFaces == 1 and numOfArrayElements != 6.

The loader implementation can store somewhere the indices of which 2D slice belongs to which face. Incomplete cubemaps have the added complexity that cubemap arrays are now harder to deal with correctly (each slice in the array could specify different completeness; unless we want to assume it's the same bitfield for all cubemaps in the cubemap array).

This feature is better supported as a 2D_ARRAY with an extra field to indicate how the cubemap should be stitched, so that programs that don't want to deal with the complexity of incomplete cubemaps can just display the whole thing as a 2D_ARRAY. It's even backwards compatible as old loaders would just ignore the new field.

3D arrays (pixelDepth > 0 && numOfArrayElements > 0);

This DOES seem to make sense because there's an impending need of requiring multiple 3D textures to handle multiple GI probes.

However I'm not sure if this need is better addressed with bindless 3D textures, as such feature allows the different probes to have different resolutions; which is something 3D arrays cannot provide.

cubemaps with 3D arrays (pixelDepth > 0 && numOfArrayElements > 0 && numOfFaces == 6).

This does not seem to make sense. Deep GBuffers perhaps? But that can be solved with cubemap arrays; since no interpolation is needed between the layers. AFAIK it's a solution looking for a problem.

MarkCallow commented 5 years ago

@darksylinc we could use metadata to provide the stitching information. If you agree, would you like to propose something?

MarkCallow commented 5 years ago

The straw poll results are

image

Based on these, incomplete cubemaps and cubemaps with 3D arrays should be invalid and since it requires no changes to KTX, 3D arrays should be valid. When we add the table we should add a note that the since the graphics APIs do not support 3D arrays, standard Vulkan and OpenGL loaders are permitted to not support such files.

Incomplete cubemaps can be supported as 2D arrays with metadata to give the face mapping as I suggested above.

Once we've decided on whether to add a Validity section as I suggested in issue #16, please send a PR.

MarkCallow commented 5 years ago

@lexaknyazev please create a PR, without adding a Validity section. It should include the table and metadata for the face mapping of a 2D array for incomplete cube maps.

lexaknyazev commented 5 years ago

metadata for the face mapping of a 2D array for incomplete cube maps

In a case of an incomplete cubemap array, could omitted faces be different for each array element?

MarkCallow commented 5 years ago

In a case of an incomplete cubemap array, could omitted faces be different for each array element?

I'm not sure I understand the question. I was expecting the array to have 1 element for each defined face and nothing for the omitted faces. The metadata would give a mapping from element index to face.

lexaknyazev commented 5 years ago

OK, let me elaborate on all cases.

Complete cubemap

Complete cubemap array

Incomplete cubemap

Array of incomplete cubemaps

So, in the last case, should we assume that missing/present faces are the same for each array element?

MarkCallow commented 5 years ago

Yes. Missing/present faces should be the same for each element.