This introduces a new device independent base class for Images in LibGPU
that also keeps track of the device from which it was created in order
to prevent assigning images across devices.
We were lacking support for default textures (i.e. calling
`glBindTexture` with a `texture` argument of `0`) which caused our
Quake2 port to render red screens whenever a video was playing. Every
texture unit is now initialized with a default 2D texture.
Additionally, we had this concept of a "currently bound target" on our
texture units which is not how OpenGL wants us to handle targets.
Calling `glBindTexture` should set the texture for the provided target
only, making it sort of an alias for future operations on the same
target.
Finally, `glDeleteTextures` should not remove the bound texture from
the target in the texture unit, but it should reset it to the default
texture.
We now sample textures from the device owned image samplers.
Passing of enabled texture units has been simplified by only passing a
list of texture unit indices.
In OpenGL, texture coordinates can have up to 4 values. This change
will help with easy application of texture coordinate matrix
transformations in the future.
Additionally, correct the initial value for texture coordinates to
`{ 0.f, 0.f, 0.f, 1.f}`.
Before, `SoftwareRasterizer` was iterating over all 32 possible texture
units for each fragment and checking each if they're bound to a texture.
After this change, an intrusive list containing only texture units with
bound textures is passed to the rasterizer. In GLQuake, this results in
a performance improvement of ~30% (from 12 to 16 FPS in the first demo)
on my machine.
Previously we multiplied the interpolated texture coordinates by
width - 1 and height - 1 instead of width and height which resulted in
some wrongly mapped textures, especially visible in the glquake light
maps.
This also corrects the wrap mode being wrongly swapped for s/t
coordinates.
Since we do not have texture borders implemented yet we always use
GL_CLAMP_TO_EDGE for all clamping wrap modes for the time being.
As stated in the manual:
glDeleteTextures silently ignores 0's and names that do not
correspond to existing textures.
If we do not skip these 0 names, they end up as invalid free texture
names in our name allocator.
These enums are used to indicate byte-alignment when reading from and
to textures. The `GL_UNPACK_ROW_LENGTH` value was reimplemented to
support overriding the source data row width.
Our existing implementation did not check the element type of the other
pointer in the constructors and move assignment operators. This meant
that some operations that would require explicit casting on raw pointers
were done implicitly, such as:
- downcasting a base class to a derived class (e.g. `Kernel::Inode` =>
`Kernel::ProcFSDirectoryInode` in Kernel/ProcFS.cpp),
- casting to an unrelated type (e.g. `Promise<bool>` => `Promise<Empty>`
in LibIMAP/Client.cpp)
This, of course, allows gross violations of the type system, and makes
the need to type-check less obvious before downcasting. Luckily, while
adding the `static_ptr_cast`s, only two truly incorrect usages were
found; in the other instances, our casts just needed to be made
explicit.
This controls how fetched texels are combined with the color that was
produced by a preceding texture unit or with the vertex color if it is
the first texture unit.
Currently only a small subset of possible combine modes is implemented
as required by glquake.
This sets the length of a row for the image to be transferred. This
value is measured in pixels. When a rectangle with a width less than
this value is transferred the remaining pixels of this row are skipped.
This extracts the sampler functionality into its own class.
Beginning with OpenGL 3 samplers are actual objects, separate
from textures. It makes sense to do this already as it also
cleans up code organization quite a bit.
The Context and Software Rasterizer now gets the array of texture units
instead of a single texture object. _Technically_, we now support some
primitive form of multi-texturing, though I'm not entirely sure how well
it will work in its current state.