mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Fix] (MG_Impl): make multisample texture storage immutable, and validate it by name
glTexStorage2DMultisample and glTexStorage3DMultisample forwarded straight to the glTexImage*Multisample allocation and stopped there. The allocation is indeed the same; what the storage forms add is that it is final - TEXTURE_IMMUTABLE_FORMAT becomes TRUE and any later call on that texture is INVALID_OPERATION (GL 4.6 core 8.19). MobileGL left the texture mutable forever, so it reported TEXTURE_IMMUTABLE_FORMAT as FALSE and accepted being respecified any number of times, silently discarding storage a test or an application had already rendered into. The by-name forms had no validation of their own either. The target forms get their target checked when the binding is resolved; reached by name there is no binding, so glTextureStorage2DMultisample took any texture, any extent and any sample count. It now rejects a target that belongs to the other entry point (INVALID_OPERATION), extents outside 1..GL_MAX_TEXTURE_SIZE and a depth past GL_MAX_ARRAY_TEXTURE_LAYERS (INVALID_VALUE), and a sample count above GL_MAX_SAMPLES (INVALID_OPERATION) - measured against the limit the getter reports rather than the backend parameter it is derived from, since the frontend raises that number. glTextureStorage1D/2D/3D gained the same treatment: a target belonging to a different one of the three is INVALID_OPERATION, a zero extent is INVALID_VALUE (immutable storage describes a real image, unlike glTexImage*D where an empty level is legal), and a level count longer than the level-zero size admits is INVALID_OPERATION. Which dimensions take part in that mip chain is per target: a 1D array keeps its layer count in height, so its height does not halve. Takes direct_state_access.textures_storage_multisample_2d_* from 0 to 30 of 30 on Espryt, and the whole group from 74.93% to 82.48%. Magma still fails them for a separate reason.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
|
||||
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
|
||||
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
||||
#include <MG_State/GLState/TextureState/TextureObjectBuffer.h>
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
@@ -300,6 +301,34 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return target == TextureTarget::Texture3D;
|
||||
}
|
||||
|
||||
// Which targets each glTextureStorage*D accepts (GL 4.6 core 8.19). A texture whose target
|
||||
// belongs to a different one of the three is the wrong object, not a bad argument, so it is
|
||||
// INVALID_OPERATION.
|
||||
Bool IsTextureStorageTargetForDimension(TextureTarget target, int dimension) {
|
||||
switch (dimension) {
|
||||
case 1:
|
||||
return target == TextureTarget::Texture1D;
|
||||
case 2:
|
||||
return target == TextureTarget::Texture2D || target == TextureTarget::Texture1DArray ||
|
||||
target == TextureTarget::TextureRectangle || target == TextureTarget::TextureCubeMap;
|
||||
case 3:
|
||||
return target == TextureTarget::Texture3D || target == TextureTarget::Texture2DArray ||
|
||||
target == TextureTarget::TextureCubeMapArray;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The longest mip chain the level-0 size admits. A 1D array keeps its layer count in
|
||||
// height, so unlike a 2D texture its height takes no part in the reduction.
|
||||
Uint ComputeFullMipmapLevelCount(const IntVec3& baseTexelSize, Bool depthMips);
|
||||
|
||||
Uint MaxTextureStorageLevels(TextureTarget target, GLsizei width, GLsizei height, GLsizei depth) {
|
||||
const Int mipHeight = (target == TextureTarget::Texture1DArray) ? 1 : std::max<Int>(height, 1);
|
||||
return ComputeFullMipmapLevelCount({std::max<Int>(width, 1), mipHeight, std::max<Int>(depth, 1)},
|
||||
DepthParticipatesInMipmapping(target));
|
||||
}
|
||||
|
||||
Uint ComputeFullMipmapLevelCount(const IntVec3& baseTexelSize, Bool depthMips) {
|
||||
Int maxDimension = std::max<Int>(
|
||||
baseTexelSize.x(),
|
||||
@@ -1591,28 +1620,28 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
}
|
||||
|
||||
void TexImage3DMultisample_State(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
Bool TexImage3DMultisample_State(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) {
|
||||
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
|
||||
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
|
||||
|
||||
if (!TextureImpl::ValidateTextureTarget(textureTarget)) return;
|
||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
||||
if (!TextureImpl::ValidateTextureTarget(textureTarget)) return false;
|
||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return false;
|
||||
if (textureTarget != TextureTarget::Texture2DMultisampleArray) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Target must be GL_TEXTURE_2D_MULTISAMPLE_ARRAY or its proxy."));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
textureInternalFormat = MG_Util::ConvertInternalFormatToSized(textureInternalFormat, TextureInputFormat::RGBA,
|
||||
TexturePixelDataType::UnsignedByte);
|
||||
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return;
|
||||
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return false;
|
||||
if (!ValidateTextureMultisampleStorage(textureTarget, samples, width, height, depth, textureInternalFormat,
|
||||
__func__))
|
||||
return;
|
||||
return false;
|
||||
|
||||
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
|
||||
auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget);
|
||||
@@ -1622,40 +1651,41 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
: bindingSlot.GetBoundObject();
|
||||
// Name 0 resolves to the target's default texture object - a real texture this call
|
||||
// (re)specifies like any other; the slot is never empty anymore.
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return false;
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture storage is not mipmap-backed."));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
AllocateMultisampleTextureStorage(textureObject, textureUploadTarget, textureInternalFormat, samples, width,
|
||||
height, depth, fixedsamplelocations);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TexImage2DMultisample_State(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
Bool TexImage2DMultisample_State(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
GLsizei height, GLboolean fixedsamplelocations) {
|
||||
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
|
||||
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
|
||||
|
||||
if (!TextureImpl::ValidateTextureTarget(textureTarget)) return;
|
||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
||||
if (!TextureImpl::ValidateTextureTarget(textureTarget)) return false;
|
||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return false;
|
||||
if (textureTarget != TextureTarget::Texture2DMultisample) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"Target must be GL_TEXTURE_2D_MULTISAMPLE or its proxy."));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
textureInternalFormat = MG_Util::ConvertInternalFormatToSized(textureInternalFormat, TextureInputFormat::RGBA,
|
||||
TexturePixelDataType::UnsignedByte);
|
||||
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return;
|
||||
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return false;
|
||||
if (!ValidateTextureMultisampleStorage(textureTarget, samples, width, height, 1, textureInternalFormat,
|
||||
__func__))
|
||||
return;
|
||||
return false;
|
||||
|
||||
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
|
||||
auto& bindingSlot = activeUnit.GetBindingSlot(textureTarget);
|
||||
@@ -1665,16 +1695,17 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
: bindingSlot.GetBoundObject();
|
||||
// Name 0 resolves to the target's default texture object - a real texture this call
|
||||
// (re)specifies like any other; the slot is never empty anymore.
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return false;
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture storage is not mipmap-backed."));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
AllocateMultisampleTextureStorage(textureObject, textureUploadTarget, textureInternalFormat, samples, width,
|
||||
height, 1, fixedsamplelocations);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TexImage3D_State(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
|
||||
@@ -3360,19 +3391,52 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
}
|
||||
|
||||
void TextureStorage1D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
// Shared front half of glTextureStorage1D/2D/3D. `dimension` selects which set of targets the
|
||||
// entry point accepts; `depth` is 1 for the lower-dimensional forms.
|
||||
static Bool ValidateTextureStorageShape(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||
int dimension, GLsizei levels, GLsizei width, GLsizei height,
|
||||
GLsizei depth, const char* caller) {
|
||||
if (levels < 1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "levels must be positive."));
|
||||
return;
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "levels must be positive."));
|
||||
return false;
|
||||
}
|
||||
if (!TextureImpl::ValidateTextureSizeRange(width, 1, 1)) return;
|
||||
// Immutable storage has to describe a real image, so unlike glTexImage*D a zero extent is
|
||||
// out of range rather than a legal empty level (GL 4.6 core 8.19).
|
||||
if (width < 1 || height < 1 || depth < 1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "width, height and depth must be positive."));
|
||||
return false;
|
||||
}
|
||||
if (!IsTextureStorageTargetForDimension(textureObject->GetTarget(), dimension)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("The effective target {} is not accepted by this entry point.",
|
||||
MG_Util::ConvertTextureTargetToString(textureObject->GetTarget()))));
|
||||
return false;
|
||||
}
|
||||
const Uint maxLevels = MaxTextureStorageLevels(textureObject->GetTarget(), width, height, depth);
|
||||
if (static_cast<Uint>(levels) > maxLevels) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("levels {} exceeds the {} the level-zero size admits.", levels, maxLevels)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureStorage1D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
|
||||
if (!ValidateTextureStorageInternalFormat(textureInternalFormat, __func__)) return;
|
||||
if (!ValidateTextureStorageShape(textureObject, 1, levels, width, 1, 1, __func__)) return;
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
@@ -3401,16 +3465,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void TextureStorage2D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
if (levels < 1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "levels must be positive."));
|
||||
return;
|
||||
}
|
||||
if (!TextureImpl::ValidateTextureSizeRange(width, height, 1)) return;
|
||||
|
||||
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
|
||||
if (!ValidateTextureStorageInternalFormat(textureInternalFormat, __func__)) return;
|
||||
if (!ValidateTextureStorageShape(textureObject, 2, levels, width, height, 1, __func__)) return;
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
@@ -3456,16 +3513,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLsizei depth) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!textureObject) return;
|
||||
if (levels < 1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "levels must be positive."));
|
||||
return;
|
||||
}
|
||||
if (!TextureImpl::ValidateTextureSizeRange(width, height, depth)) return;
|
||||
|
||||
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
|
||||
if (!ValidateTextureStorageInternalFormat(textureInternalFormat, __func__)) return;
|
||||
if (!ValidateTextureStorageShape(textureObject, 3, levels, width, height, depth, __func__)) return;
|
||||
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
@@ -3506,9 +3556,68 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
textureObject->SetImmutableLevels(static_cast<Uint>(levels));
|
||||
}
|
||||
|
||||
// Shared front half of glTextureStorage2DMultisample/3DMultisample. The target forms are reached
|
||||
// through a binding and get their target validated there; by name the object itself has to be
|
||||
// checked, and so do the extents, which the binding path never sees (GL 4.6 core 8.19).
|
||||
static Bool ValidateNamedMultisampleStorage(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||
TextureTarget expectedTarget, GLsizei samples, GLsizei width,
|
||||
GLsizei height, GLsizei depth, const char* caller) {
|
||||
if (!textureObject) return false;
|
||||
if (textureObject->GetTarget() != expectedTarget) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("The effective target {} is not accepted by this entry point.",
|
||||
MG_Util::ConvertTextureTargetToString(textureObject->GetTarget()))));
|
||||
return false;
|
||||
}
|
||||
if (width < 1 || height < 1 || depth < 1) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "width, height and depth must be positive."));
|
||||
return false;
|
||||
}
|
||||
const auto& limits = MG_Backend::pActiveBackendObject->GetDynamicParameters();
|
||||
if (width > limits.MaxTextureSize || height > limits.MaxTextureSize) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
"width and height must not exceed GL_MAX_TEXTURE_SIZE."));
|
||||
return false;
|
||||
}
|
||||
if (depth > limits.MaxArrayTextureLayers) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
"depth must not exceed GL_MAX_ARRAY_TEXTURE_LAYERS."));
|
||||
return false;
|
||||
}
|
||||
// More samples than the implementation offers is a request it cannot serve rather than a
|
||||
// malformed argument, so INVALID_OPERATION and not INVALID_VALUE. The limit comes from the
|
||||
// getter rather than the backend parameter it is derived from, because the frontend raises
|
||||
// that number - validating against the raw one would reject a count GL_MAX_SAMPLES
|
||||
// advertises.
|
||||
GLint maxSamples = 1;
|
||||
GetIntegerv(GL_MAX_SAMPLES, &maxSamples);
|
||||
if (samples > maxSamples) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "samples exceeds GL_MAX_SAMPLES."));
|
||||
return false;
|
||||
}
|
||||
// Storage is defined once. The mipmap forms go through ValidateTextureMutable for this; the
|
||||
// multisample ones reached the backend without ever asking.
|
||||
if (!ValidateTextureMutable(textureObject, caller)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureStorage2DMultisample(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
GLsizei height, GLboolean fixedsamplelocations) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!ValidateNamedMultisampleStorage(textureObject, TextureTarget::Texture2DMultisample, samples, width, height,
|
||||
1, __func__))
|
||||
return;
|
||||
WithTemporarilyBoundNamedTexture(textureObject, [&](GLenum target) {
|
||||
TexStorage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations);
|
||||
});
|
||||
@@ -3517,6 +3626,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void TextureStorage3DMultisample(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) {
|
||||
auto textureObject = GetTextureObjectByName(texture, __func__);
|
||||
if (!ValidateNamedMultisampleStorage(textureObject, TextureTarget::Texture2DMultisampleArray, samples, width,
|
||||
height, depth, __func__))
|
||||
return;
|
||||
WithTemporarilyBoundNamedTexture(textureObject, [&](GLenum target) {
|
||||
TexStorage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations);
|
||||
});
|
||||
@@ -3568,14 +3680,40 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
TextureStorage3D(textureObject->GetExternalIndex(), levels, internalformat, width, height, depth);
|
||||
}
|
||||
|
||||
// The multisample storage forms allocate exactly what the glTexImage*Multisample ones do, and
|
||||
// then freeze it: TEXTURE_IMMUTABLE_FORMAT becomes TRUE and a second call is INVALID_OPERATION
|
||||
// (GL 4.6 core 8.19). Only the allocation was shared before, so a multisample texture stayed
|
||||
// mutable forever and could be respecified any number of times.
|
||||
static void TexStorageMultisample_State(GLenum target, Bool allocated, const char* caller) {
|
||||
static_cast<void>(caller);
|
||||
if (!allocated) return;
|
||||
const TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
if (TextureImpl::IsProxyTextureTarget(MG_Util::ConvertGLEnumToTextureUploadTarget(target))) return;
|
||||
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
|
||||
auto& textureObject = activeUnit.GetBindingSlot(textureTarget).GetBoundObject();
|
||||
if (!textureObject) return;
|
||||
textureObject->SetImmutableLevels(1);
|
||||
}
|
||||
|
||||
void TexStorage2DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
GLsizei height, GLboolean fixedsamplelocations) {
|
||||
TexImage2DMultisample_State(target, samples, internalformat, width, height, fixedsamplelocations);
|
||||
const TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
|
||||
if (!ValidateTextureMutable(activeUnit.GetBindingSlot(textureTarget).GetBoundObject(), __func__)) return;
|
||||
TexStorageMultisample_State(
|
||||
target, TexImage2DMultisample_State(target, samples, internalformat, width, height, fixedsamplelocations),
|
||||
__func__);
|
||||
}
|
||||
|
||||
void TexStorage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
|
||||
GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) {
|
||||
TexImage3DMultisample_State(target, samples, internalformat, width, height, depth, fixedsamplelocations);
|
||||
const TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
|
||||
if (!ValidateTextureMutable(activeUnit.GetBindingSlot(textureTarget).GetBoundObject(), __func__)) return;
|
||||
TexStorageMultisample_State(target,
|
||||
TexImage3DMultisample_State(target, samples, internalformat, width, height, depth,
|
||||
fixedsamplelocations),
|
||||
__func__);
|
||||
}
|
||||
|
||||
void TextureSubImage1D(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type,
|
||||
|
||||
Reference in New Issue
Block a user