RHI: Add support for 1D textures
Support for 1D textures on Vulkan, OpenGL, Metal, and D3D. Change-Id: Ie74ec103da9cfcbf83fa78588cf8cfc1bd6e104f Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>bb10
parent
a47c7a9826
commit
85a1663eb1
|
|
@ -727,6 +727,15 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
|
|||
for changing the mode to Line is to get wireframe rendering. This however
|
||||
is not available as a core OpenGL ES feature, and is optional with Vulkan
|
||||
as well as some mobile GPUs may not offer the feature.
|
||||
|
||||
\value OneDimensionalTextures Indicates that 1D textures are supported.
|
||||
In practice this feature will be unsupported on OpenGL ES.
|
||||
|
||||
\value OneDimensionalTextureMipmaps Indicates that 1D texture mipmaps and
|
||||
1D texture render targets are supported. In practice this feature will be
|
||||
unsupported on backends that do not report support for
|
||||
\l{OneDimensionalTextures}, and Metal.
|
||||
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
|
@ -7296,14 +7305,21 @@ QRhiRenderBuffer *QRhi::newRenderBuffer(QRhiRenderBuffer::Type type,
|
|||
}
|
||||
|
||||
/*!
|
||||
\return a new 2D texture with the specified \a format, \a pixelSize, \a
|
||||
\return a new 1D or 2D texture with the specified \a format, \a pixelSize, \a
|
||||
sampleCount, and \a flags.
|
||||
|
||||
A 1D texture array must have QRhiTexture::OneDimensional set in \a flags. This
|
||||
function will implicitly set this flag if the \a pixelSize height is 0.
|
||||
|
||||
\note \a format specifies the requested internal and external format,
|
||||
meaning the data to be uploaded to the texture will need to be in a
|
||||
compatible format, while the native texture may (but is not guaranteed to,
|
||||
in case of OpenGL at least) use this format internally.
|
||||
|
||||
\note 1D textures are only functional when the OneDimensionalTextures feature is
|
||||
reported as supported at run time. Further, mipmaps on 1D textures are only
|
||||
functional when the OneDimensionalTextureMipmaps feature is reported at run time.
|
||||
|
||||
\sa QRhiResource::destroy()
|
||||
*/
|
||||
QRhiTexture *QRhi::newTexture(QRhiTexture::Format format,
|
||||
|
|
@ -7311,22 +7327,32 @@ QRhiTexture *QRhi::newTexture(QRhiTexture::Format format,
|
|||
int sampleCount,
|
||||
QRhiTexture::Flags flags)
|
||||
{
|
||||
if (pixelSize.height() == 0)
|
||||
flags |= QRhiTexture::OneDimensional;
|
||||
|
||||
return d->createTexture(format, pixelSize, 1, 0, sampleCount, flags);
|
||||
}
|
||||
|
||||
/*!
|
||||
\return a new 2D or 3D texture with the specified \a format, \a width, \a
|
||||
\return a new 1D, 2D or 3D texture with the specified \a format, \a width, \a
|
||||
height, \a depth, \a sampleCount, and \a flags.
|
||||
|
||||
This overload is suitable for 3D textures because it allows specifying \a
|
||||
depth. A 3D texture must have QRhiTexture::ThreeDimensional set in \a
|
||||
flags, but using this overload that can be omitted because the flag is set
|
||||
implicitly whenever \a depth is greater than 0. For 2D and cube textures \a
|
||||
implicitly whenever \a depth is greater than 0. For 1D, 2D and cube textures \a
|
||||
depth should be set to 0.
|
||||
|
||||
A 1D texture must have QRhiTexture::OneDimensional set in \a flags. This overload
|
||||
will implicitly set this flag if both \a height and \a depth are 0.
|
||||
|
||||
\note 3D textures are only functional when the ThreeDimensionalTextures
|
||||
feature is reported as supported at run time.
|
||||
|
||||
\note 1D textures are only functional when the OneDimensionalTextures feature is
|
||||
reported as supported at run time. Further, mipmaps on 1D textures are only
|
||||
functional when the OneDimensionalTextureMipmaps feature is reported at run time.
|
||||
|
||||
\overload
|
||||
*/
|
||||
QRhiTexture *QRhi::newTexture(QRhiTexture::Format format,
|
||||
|
|
@ -7337,17 +7363,23 @@ QRhiTexture *QRhi::newTexture(QRhiTexture::Format format,
|
|||
if (depth > 0)
|
||||
flags |= QRhiTexture::ThreeDimensional;
|
||||
|
||||
if (height == 0 && depth == 0)
|
||||
flags |= QRhiTexture::OneDimensional;
|
||||
|
||||
return d->createTexture(format, QSize(width, height), depth, 0, sampleCount, flags);
|
||||
}
|
||||
|
||||
/*!
|
||||
\return a new 2D texture array with the specified \a format, \a arraySize,
|
||||
\return a new 1D or 2D texture array with the specified \a format, \a arraySize,
|
||||
\a pixelSize, \a sampleCount, and \a flags.
|
||||
|
||||
This function implicitly sets QRhiTexture::TextureArray in \a flags.
|
||||
|
||||
A 1D texture array must have QRhiTexture::OneDimensional set in \a flags. This
|
||||
function will implicitly set this flag if the \a pixelSize height is 0.
|
||||
|
||||
\note Do not confuse texture arrays with arrays of textures. A QRhiTexture
|
||||
created by this function is usable with 2D array samplers in the shader, for
|
||||
created by this function is usable with 1D or 2D array samplers in the shader, for
|
||||
example: \c{layout(binding = 1) uniform sampler2DArray texArr;}. Arrays of
|
||||
textures refers to a list of textures that are exposed to the shader via
|
||||
QRhiShaderResourceBinding::sampledTextures() and a count > 1, and declared
|
||||
|
|
@ -7357,6 +7389,11 @@ QRhiTexture *QRhi::newTexture(QRhiTexture::Format format,
|
|||
\note This is only functional when the TextureArrays feature is reported as
|
||||
supported at run time.
|
||||
|
||||
\note 1D textures are only functional when the OneDimensionalTextures feature is
|
||||
reported as supported at run time. Further, mipmaps on 1D textures are only
|
||||
functional when the OneDimensionalTextureMipmaps feature is reported at run time.
|
||||
|
||||
|
||||
\sa newTexture()
|
||||
*/
|
||||
QRhiTexture *QRhi::newTextureArray(QRhiTexture::Format format,
|
||||
|
|
@ -7366,6 +7403,10 @@ QRhiTexture *QRhi::newTextureArray(QRhiTexture::Format format,
|
|||
QRhiTexture::Flags flags)
|
||||
{
|
||||
flags |= QRhiTexture::TextureArray;
|
||||
|
||||
if (pixelSize.height() == 0)
|
||||
flags |= QRhiTexture::OneDimensional;
|
||||
|
||||
return d->createTexture(format, pixelSize, 1, arraySize, sampleCount, flags);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -760,7 +760,8 @@ public:
|
|||
ExternalOES = 1 << 9,
|
||||
ThreeDimensional = 1 << 10,
|
||||
TextureRectangleGL = 1 << 11,
|
||||
TextureArray = 1 << 12
|
||||
TextureArray = 1 << 12,
|
||||
OneDimensional = 1 << 13
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
|
|
@ -1672,7 +1673,9 @@ public:
|
|||
Tessellation,
|
||||
GeometryShader,
|
||||
TextureArrayRange,
|
||||
NonFillPolygonMode
|
||||
NonFillPolygonMode,
|
||||
OneDimensionalTextures,
|
||||
OneDimensionalTextureMipmaps
|
||||
};
|
||||
|
||||
enum BeginFrameFlag {
|
||||
|
|
|
|||
|
|
@ -543,6 +543,10 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
|
|||
return true;
|
||||
case QRhi::NonFillPolygonMode:
|
||||
return true;
|
||||
case QRhi::OneDimensionalTextures:
|
||||
return true;
|
||||
case QRhi::OneDimensionalTextureMipmaps:
|
||||
return true;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
return false;
|
||||
|
|
@ -3057,7 +3061,7 @@ QD3D11Texture::~QD3D11Texture()
|
|||
|
||||
void QD3D11Texture::destroy()
|
||||
{
|
||||
if (!tex && !tex3D)
|
||||
if (!tex && !tex3D && !tex1D)
|
||||
return;
|
||||
|
||||
if (srv) {
|
||||
|
|
@ -3077,10 +3081,13 @@ void QD3D11Texture::destroy()
|
|||
tex->Release();
|
||||
if (tex3D)
|
||||
tex3D->Release();
|
||||
if (tex1D)
|
||||
tex1D->Release();
|
||||
}
|
||||
|
||||
tex = nullptr;
|
||||
tex3D = nullptr;
|
||||
tex1D = nullptr;
|
||||
|
||||
QRHI_RES_RHI(QRhiD3D11);
|
||||
if (rhiD)
|
||||
|
|
@ -3123,15 +3130,18 @@ static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
|
|||
|
||||
bool QD3D11Texture::prepareCreate(QSize *adjustedSize)
|
||||
{
|
||||
if (tex || tex3D)
|
||||
if (tex || tex3D || tex1D)
|
||||
destroy();
|
||||
|
||||
const QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
|
||||
const bool isDepth = isDepthTextureFormat(m_format);
|
||||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
|
||||
const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
|
||||
: (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
|
||||
|
||||
QRHI_RES_RHI(QRhiD3D11);
|
||||
dxgiFormat = toD3DTextureFormat(m_format, m_flags);
|
||||
|
|
@ -3163,6 +3173,14 @@ bool QD3D11Texture::prepareCreate(QSize *adjustedSize)
|
|||
qWarning("Texture cannot be both array and 3D");
|
||||
return false;
|
||||
}
|
||||
if (isCube && is1D) {
|
||||
qWarning("Texture cannot be both cube and 1D");
|
||||
return false;
|
||||
}
|
||||
if (is1D && is3D) {
|
||||
qWarning("Texture cannot be both 1D and 3D");
|
||||
return false;
|
||||
}
|
||||
m_depth = qMax(1, m_depth);
|
||||
if (m_depth > 1 && !is3D) {
|
||||
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
|
||||
|
|
@ -3191,6 +3209,7 @@ bool QD3D11Texture::finishCreate()
|
|||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = isDepth ? toD3DDepthTextureSRVFormat(m_format) : dxgiFormat;
|
||||
|
|
@ -3198,7 +3217,22 @@ bool QD3D11Texture::finishCreate()
|
|||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
|
||||
srvDesc.TextureCube.MipLevels = mipLevelCount;
|
||||
} else {
|
||||
if (isArray) {
|
||||
if (is1D) {
|
||||
if (isArray) {
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
|
||||
srvDesc.Texture1DArray.MipLevels = mipLevelCount;
|
||||
if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
|
||||
srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
|
||||
srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
|
||||
} else {
|
||||
srvDesc.Texture1DArray.FirstArraySlice = 0;
|
||||
srvDesc.Texture1DArray.ArraySize = UINT(m_arraySize);
|
||||
}
|
||||
} else {
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
|
||||
srvDesc.Texture1D.MipLevels = mipLevelCount;
|
||||
}
|
||||
} else if (isArray) {
|
||||
if (sampleDesc.Count > 1) {
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
|
||||
if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
|
||||
|
|
@ -3252,6 +3286,7 @@ bool QD3D11Texture::create()
|
|||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
|
||||
uint bindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
uint miscFlags = isCube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
|
||||
|
|
@ -3273,7 +3308,25 @@ bool QD3D11Texture::create()
|
|||
bindFlags |= D3D11_BIND_UNORDERED_ACCESS;
|
||||
|
||||
QRHI_RES_RHI(QRhiD3D11);
|
||||
if (!is3D) {
|
||||
if (is1D) {
|
||||
D3D11_TEXTURE1D_DESC desc = {};
|
||||
desc.Width = UINT(size.width());
|
||||
desc.MipLevels = mipLevelCount;
|
||||
desc.ArraySize = isArray ? UINT(m_arraySize) : 1;
|
||||
desc.Format = dxgiFormat;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = bindFlags;
|
||||
desc.MiscFlags = miscFlags;
|
||||
|
||||
HRESULT hr = rhiD->dev->CreateTexture1D(&desc, nullptr, &tex1D);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Failed to create 1D texture: %s", qPrintable(comErrorMessage(hr)));
|
||||
return false;
|
||||
}
|
||||
if (!m_objectName.isEmpty())
|
||||
tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()),
|
||||
m_objectName.constData());
|
||||
} else if (!is3D) {
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = UINT(size.width());
|
||||
desc.Height = UINT(size.height());
|
||||
|
|
@ -3330,6 +3383,8 @@ bool QD3D11Texture::createFrom(QRhiTexture::NativeTexture src)
|
|||
|
||||
if (m_flags.testFlag(ThreeDimensional))
|
||||
tex3D = reinterpret_cast<ID3D11Texture3D *>(src.object);
|
||||
else if (m_flags.testFlags(OneDimensional))
|
||||
tex1D = reinterpret_cast<ID3D11Texture1D *>(src.object);
|
||||
else
|
||||
tex = reinterpret_cast<ID3D11Texture2D *>(src.object);
|
||||
|
||||
|
|
@ -3649,6 +3704,16 @@ bool QD3D11TextureRenderTarget::create()
|
|||
rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
|
||||
rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
|
||||
rtvDesc.Texture2DArray.ArraySize = 1;
|
||||
} else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
|
||||
if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
|
||||
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY;
|
||||
rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
|
||||
rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
|
||||
rtvDesc.Texture1DArray.ArraySize = 1;
|
||||
} else {
|
||||
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D;
|
||||
rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
|
||||
}
|
||||
} else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
|
||||
if (texD->sampleDesc.Count > 1) {
|
||||
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
|
||||
|
|
|
|||
|
|
@ -82,11 +82,14 @@ struct QD3D11Texture : public QRhiTexture
|
|||
{
|
||||
if (tex)
|
||||
return tex;
|
||||
else if (tex1D)
|
||||
return tex1D;
|
||||
return tex3D;
|
||||
}
|
||||
|
||||
ID3D11Texture2D *tex = nullptr;
|
||||
ID3D11Texture3D *tex3D = nullptr;
|
||||
ID3D11Texture1D *tex1D = nullptr;
|
||||
bool owns = true;
|
||||
ID3D11ShaderResourceView *srv = nullptr;
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
|
|
|
|||
|
|
@ -443,6 +443,14 @@ QT_BEGIN_NAMESPACE
|
|||
#define GL_BACK_RIGHT 0x0403
|
||||
#endif
|
||||
|
||||
#ifndef GL_TEXTURE_1D
|
||||
# define GL_TEXTURE_1D 0x0DE0
|
||||
#endif
|
||||
|
||||
#ifndef GL_TEXTURE_1D_ARRAY
|
||||
# define GL_TEXTURE_1D_ARRAY 0x8C18
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Constructs a new QRhiGles2InitParams.
|
||||
|
||||
|
|
@ -647,8 +655,38 @@ bool QRhiGles2::create(QRhi::Flags flags)
|
|||
return false;
|
||||
|
||||
f = static_cast<QOpenGLExtensions *>(ctx->extraFunctions());
|
||||
glPolygonMode = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum)>(
|
||||
ctx->getProcAddress(QByteArrayLiteral("glPolygonMode")));
|
||||
|
||||
if (!caps.gles) {
|
||||
glPolygonMode = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum)>(
|
||||
ctx->getProcAddress(QByteArrayLiteral("glPolygonMode")));
|
||||
|
||||
glTexImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(
|
||||
GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, const void *)>(
|
||||
ctx->getProcAddress(QByteArrayLiteral("glTexImage1D")));
|
||||
|
||||
glTexStorage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei)>(
|
||||
ctx->getProcAddress(QByteArrayLiteral("glTexStorage1D")));
|
||||
|
||||
glTexSubImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(
|
||||
GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *)>(
|
||||
ctx->getProcAddress(QByteArrayLiteral("glTexSubImage1D")));
|
||||
|
||||
glCopyTexSubImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint,
|
||||
GLint, GLsizei)>(
|
||||
ctx->getProcAddress(QByteArrayLiteral("glCopyTexSubImage1D")));
|
||||
|
||||
glCompressedTexImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(
|
||||
GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid *)>(
|
||||
ctx->getProcAddress(QByteArrayLiteral("glCompressedTexImage1D")));
|
||||
|
||||
glCompressedTexSubImage1D = reinterpret_cast<void(QOPENGLF_APIENTRYP)(
|
||||
GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid *)>(
|
||||
ctx->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage1D")));
|
||||
|
||||
glFramebufferTexture1D =
|
||||
reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum, GLenum, GLuint, GLint)>(
|
||||
ctx->getProcAddress(QByteArrayLiteral("glFramebufferTexture1D")));
|
||||
}
|
||||
|
||||
const char *vendor = reinterpret_cast<const char *>(f->glGetString(GL_VENDOR));
|
||||
const char *renderer = reinterpret_cast<const char *>(f->glGetString(GL_RENDERER));
|
||||
|
|
@ -847,6 +885,11 @@ bool QRhiGles2::create(QRhi::Flags flags)
|
|||
|
||||
caps.texture3D = caps.ctxMajor >= 3; // 3.0
|
||||
|
||||
if (caps.gles)
|
||||
caps.texture1D = false; // ES
|
||||
else
|
||||
caps.texture1D = glTexImage1D && (caps.ctxMajor >= 2); // 2.0
|
||||
|
||||
if (caps.gles)
|
||||
caps.tessellation = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2); // ES 3.2
|
||||
else
|
||||
|
|
@ -1262,6 +1305,10 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
|
|||
return false;
|
||||
case QRhi::NonFillPolygonMode:
|
||||
return !caps.gles;
|
||||
case QRhi::OneDimensionalTextures:
|
||||
return caps.texture1D;
|
||||
case QRhi::OneDimensionalTextureMipmaps:
|
||||
return caps.texture1D;
|
||||
default:
|
||||
Q_UNREACHABLE_RETURN(false);
|
||||
}
|
||||
|
|
@ -2092,6 +2139,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
|
|||
const bool isCompressed = isCompressedFormat(texD->m_format);
|
||||
const bool isCubeMap = texD->m_flags.testFlag(QRhiTexture::CubeMap);
|
||||
const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
|
||||
const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
|
||||
const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
|
||||
const GLenum faceTargetBase = isCubeMap ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
|
||||
const GLenum effectiveTarget = faceTargetBase + (isCubeMap ? uint(layer) : 0u);
|
||||
|
|
@ -2113,7 +2161,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
|
|||
cmd.args.subImage.faceTarget = effectiveTarget;
|
||||
cmd.args.subImage.level = level;
|
||||
cmd.args.subImage.dx = dp.x();
|
||||
cmd.args.subImage.dy = dp.y();
|
||||
cmd.args.subImage.dy = is1D && isArray ? layer : dp.y();
|
||||
cmd.args.subImage.dz = is3D || isArray ? layer : 0;
|
||||
cmd.args.subImage.w = size.width();
|
||||
cmd.args.subImage.h = size.height();
|
||||
|
|
@ -2146,7 +2194,8 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
|
|||
cmd.args.compressedImage.level = level;
|
||||
cmd.args.compressedImage.glintformat = texD->glintformat;
|
||||
cmd.args.compressedImage.w = texD->m_pixelSize.width();
|
||||
cmd.args.compressedImage.h = texD->m_pixelSize.height();
|
||||
cmd.args.compressedImage.h =
|
||||
is1D && isArray ? texD->m_arraySize : texD->m_pixelSize.height();
|
||||
cmd.args.compressedImage.depth = is3D ? texD->m_depth : (isArray ? texD->m_arraySize : 0);
|
||||
cmd.args.compressedImage.size = byteSize;
|
||||
cmd.args.compressedImage.data = cbD->retainData(zeroBuf);
|
||||
|
|
@ -2163,7 +2212,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
|
|||
cmd.args.compressedSubImage.faceTarget = effectiveTarget;
|
||||
cmd.args.compressedSubImage.level = level;
|
||||
cmd.args.compressedSubImage.dx = dp.x();
|
||||
cmd.args.compressedSubImage.dy = dp.y();
|
||||
cmd.args.compressedSubImage.dy = is1D && isArray ? layer : dp.y();
|
||||
cmd.args.compressedSubImage.dz = is3D || isArray ? layer : 0;
|
||||
cmd.args.compressedSubImage.w = size.width();
|
||||
cmd.args.compressedSubImage.h = size.height();
|
||||
|
|
@ -2179,7 +2228,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
|
|||
cmd.args.compressedImage.level = level;
|
||||
cmd.args.compressedImage.glintformat = texD->glintformat;
|
||||
cmd.args.compressedImage.w = size.width();
|
||||
cmd.args.compressedImage.h = size.height();
|
||||
cmd.args.compressedImage.h = is1D && isArray ? texD->m_arraySize : size.height();
|
||||
cmd.args.compressedImage.depth = is3D ? texD->m_depth : (isArray ? texD->m_arraySize : 0);
|
||||
cmd.args.compressedImage.size = rawData.size();
|
||||
cmd.args.compressedImage.data = cbD->retainData(rawData);
|
||||
|
|
@ -2197,7 +2246,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
|
|||
cmd.args.subImage.faceTarget = effectiveTarget;
|
||||
cmd.args.subImage.level = level;
|
||||
cmd.args.subImage.dx = dp.x();
|
||||
cmd.args.subImage.dy = dp.y();
|
||||
cmd.args.subImage.dy = is1D && isArray ? layer : dp.y();
|
||||
cmd.args.subImage.dz = is3D || isArray ? layer : 0;
|
||||
cmd.args.subImage.w = size.width();
|
||||
cmd.args.subImage.h = size.height();
|
||||
|
|
@ -2309,6 +2358,8 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||
|
||||
const bool srcHasZ = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional) || srcD->m_flags.testFlag(QRhiTexture::TextureArray);
|
||||
const bool dstHasZ = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional) || dstD->m_flags.testFlag(QRhiTexture::TextureArray);
|
||||
const bool dstIs1dArray = dstD->m_flags.testFlag(QRhiTexture::OneDimensional)
|
||||
&& dstD->m_flags.testFlag(QRhiTexture::TextureArray);
|
||||
|
||||
cmd.args.copyTex.srcTarget = srcD->target;
|
||||
cmd.args.copyTex.srcFaceTarget = srcFaceTargetBase + (srcHasZ ? 0u : uint(u.desc.sourceLayer()));
|
||||
|
|
@ -2323,7 +2374,7 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||
cmd.args.copyTex.dstTexture = dstD->texture;
|
||||
cmd.args.copyTex.dstLevel = u.desc.destinationLevel();
|
||||
cmd.args.copyTex.dstX = dp.x();
|
||||
cmd.args.copyTex.dstY = dp.y();
|
||||
cmd.args.copyTex.dstY = dstIs1dArray ? u.desc.destinationLayer() : dp.y();
|
||||
cmd.args.copyTex.dstZ = dstHasZ ? u.desc.destinationLayer() : 0;
|
||||
|
||||
cmd.args.copyTex.w = copySize.width();
|
||||
|
|
@ -3085,9 +3136,15 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||
GLuint fbo;
|
||||
f->glGenFramebuffers(1, &fbo);
|
||||
f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
if (cmd.args.copyTex.srcTarget == GL_TEXTURE_3D || cmd.args.copyTex.srcTarget == GL_TEXTURE_2D_ARRAY) {
|
||||
if (cmd.args.copyTex.srcTarget == GL_TEXTURE_3D
|
||||
|| cmd.args.copyTex.srcTarget == GL_TEXTURE_2D_ARRAY
|
||||
|| cmd.args.copyTex.srcTarget == GL_TEXTURE_1D_ARRAY) {
|
||||
f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cmd.args.copyTex.srcTexture,
|
||||
cmd.args.copyTex.srcLevel, cmd.args.copyTex.srcZ);
|
||||
} else if (cmd.args.copyTex.srcTarget == GL_TEXTURE_1D) {
|
||||
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
cmd.args.copyTex.srcTarget, cmd.args.copyTex.srcTexture,
|
||||
cmd.args.copyTex.srcLevel);
|
||||
} else {
|
||||
f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
cmd.args.copyTex.srcFaceTarget, cmd.args.copyTex.srcTexture, cmd.args.copyTex.srcLevel);
|
||||
|
|
@ -3098,6 +3155,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||
cmd.args.copyTex.dstX, cmd.args.copyTex.dstY, cmd.args.copyTex.dstZ,
|
||||
cmd.args.copyTex.srcX, cmd.args.copyTex.srcY,
|
||||
cmd.args.copyTex.w, cmd.args.copyTex.h);
|
||||
} else if (cmd.args.copyTex.dstTarget == GL_TEXTURE_1D) {
|
||||
glCopyTexSubImage1D(cmd.args.copyTex.dstTarget, cmd.args.copyTex.dstLevel,
|
||||
cmd.args.copyTex.dstX, cmd.args.copyTex.srcX,
|
||||
cmd.args.copyTex.srcY, cmd.args.copyTex.w);
|
||||
} else {
|
||||
f->glCopyTexSubImage2D(cmd.args.copyTex.dstFaceTarget, cmd.args.copyTex.dstLevel,
|
||||
cmd.args.copyTex.dstX, cmd.args.copyTex.dstY,
|
||||
|
|
@ -3124,6 +3185,9 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||
if (cmd.args.readPixels.slice3D >= 0) {
|
||||
f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
tex, mipLevel, cmd.args.readPixels.slice3D);
|
||||
} else if (cmd.args.readPixels.readTarget == GL_TEXTURE_1D) {
|
||||
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
cmd.args.readPixels.readTarget, tex, mipLevel);
|
||||
} else {
|
||||
f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
cmd.args.readPixels.readTarget, tex, mipLevel);
|
||||
|
|
@ -3203,6 +3267,11 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||
cmd.args.subImage.w, cmd.args.subImage.h, 1,
|
||||
cmd.args.subImage.glformat, cmd.args.subImage.gltype,
|
||||
cmd.args.subImage.data);
|
||||
} else if (cmd.args.subImage.target == GL_TEXTURE_1D) {
|
||||
glTexSubImage1D(cmd.args.subImage.target, cmd.args.subImage.level,
|
||||
cmd.args.subImage.dx, cmd.args.subImage.w,
|
||||
cmd.args.subImage.glformat, cmd.args.subImage.gltype,
|
||||
cmd.args.subImage.data);
|
||||
} else {
|
||||
f->glTexSubImage2D(cmd.args.subImage.faceTarget, cmd.args.subImage.level,
|
||||
cmd.args.subImage.dx, cmd.args.subImage.dy,
|
||||
|
|
@ -3222,6 +3291,11 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||
cmd.args.compressedImage.glintformat,
|
||||
cmd.args.compressedImage.w, cmd.args.compressedImage.h, cmd.args.compressedImage.depth,
|
||||
0, cmd.args.compressedImage.size, cmd.args.compressedImage.data);
|
||||
} else if (cmd.args.compressedImage.target == GL_TEXTURE_1D) {
|
||||
glCompressedTexImage1D(
|
||||
cmd.args.compressedImage.target, cmd.args.compressedImage.level,
|
||||
cmd.args.compressedImage.glintformat, cmd.args.compressedImage.w, 0,
|
||||
cmd.args.compressedImage.size, cmd.args.compressedImage.data);
|
||||
} else {
|
||||
f->glCompressedTexImage2D(cmd.args.compressedImage.faceTarget, cmd.args.compressedImage.level,
|
||||
cmd.args.compressedImage.glintformat,
|
||||
|
|
@ -3237,6 +3311,12 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||
cmd.args.compressedSubImage.w, cmd.args.compressedSubImage.h, 1,
|
||||
cmd.args.compressedSubImage.glintformat,
|
||||
cmd.args.compressedSubImage.size, cmd.args.compressedSubImage.data);
|
||||
} else if (cmd.args.compressedImage.target == GL_TEXTURE_1D) {
|
||||
glCompressedTexSubImage1D(
|
||||
cmd.args.compressedSubImage.target, cmd.args.compressedSubImage.level,
|
||||
cmd.args.compressedSubImage.dx, cmd.args.compressedSubImage.w,
|
||||
cmd.args.compressedSubImage.glintformat, cmd.args.compressedSubImage.size,
|
||||
cmd.args.compressedSubImage.data);
|
||||
} else {
|
||||
f->glCompressedTexSubImage2D(cmd.args.compressedSubImage.faceTarget, cmd.args.compressedSubImage.level,
|
||||
cmd.args.compressedSubImage.dx, cmd.args.compressedSubImage.dy,
|
||||
|
|
@ -5005,13 +5085,15 @@ bool QGles2Texture::prepareCreate(QSize *adjustedSize)
|
|||
if (!rhiD->ensureContext())
|
||||
return false;
|
||||
|
||||
const QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
|
||||
|
||||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool isArray = m_flags.testFlag(QRhiTexture::TextureArray);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
||||
const bool isCompressed = rhiD->isCompressedFormat(m_format);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
|
||||
const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
|
||||
: (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
|
||||
|
||||
if (is3D && !rhiD->caps.texture3D) {
|
||||
qWarning("3D textures are not supported");
|
||||
|
|
@ -5025,6 +5107,19 @@ bool QGles2Texture::prepareCreate(QSize *adjustedSize)
|
|||
qWarning("Texture cannot be both array and 3D");
|
||||
return false;
|
||||
}
|
||||
if (is1D && !rhiD->caps.texture1D) {
|
||||
qWarning("1D textures are not supported");
|
||||
return false;
|
||||
}
|
||||
if (is1D && is3D) {
|
||||
qWarning("Texture cannot be both 1D and 3D");
|
||||
return false;
|
||||
}
|
||||
if (is1D && isCube) {
|
||||
qWarning("Texture cannot be both 1D and cube");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_depth = qMax(1, m_depth);
|
||||
if (m_depth > 1 && !is3D) {
|
||||
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
|
||||
|
|
@ -5040,9 +5135,12 @@ bool QGles2Texture::prepareCreate(QSize *adjustedSize)
|
|||
return false;
|
||||
}
|
||||
|
||||
target = isCube ? GL_TEXTURE_CUBE_MAP
|
||||
: m_sampleCount > 1 ? GL_TEXTURE_2D_MULTISAMPLE
|
||||
: (is3D ? GL_TEXTURE_3D : (isArray ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D));
|
||||
target = isCube ? GL_TEXTURE_CUBE_MAP
|
||||
: m_sampleCount > 1 ? GL_TEXTURE_2D_MULTISAMPLE
|
||||
: (is3D ? GL_TEXTURE_3D
|
||||
: (is1D ? (isArray ? GL_TEXTURE_1D_ARRAY : GL_TEXTURE_1D)
|
||||
: (isArray ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D)));
|
||||
|
||||
if (m_flags.testFlag(ExternalOES))
|
||||
target = GL_TEXTURE_EXTERNAL_OES;
|
||||
else if (m_flags.testFlag(TextureRectangleGL))
|
||||
|
|
@ -5092,10 +5190,22 @@ bool QGles2Texture::create()
|
|||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
||||
const bool isCompressed = rhiD->isCompressedFormat(m_format);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
|
||||
if (!isCompressed) {
|
||||
rhiD->f->glBindTexture(target, texture);
|
||||
if (!m_flags.testFlag(UsedWithLoadStore)) {
|
||||
if (is3D || isArray) {
|
||||
if (is1D) {
|
||||
for (int level = 0; level < mipLevelCount; ++level) {
|
||||
const QSize mipSize = rhiD->q->sizeForMipLevel(level, size);
|
||||
if (isArray)
|
||||
rhiD->f->glTexImage2D(target, level, GLint(glintformat), mipSize.width(),
|
||||
m_arraySize, 0, glformat, gltype, nullptr);
|
||||
else
|
||||
rhiD->glTexImage1D(target, level, GLint(glintformat), mipSize.width(), 0,
|
||||
glformat, gltype, nullptr);
|
||||
}
|
||||
} else if (is3D || isArray) {
|
||||
const int layerCount = is3D ? m_depth : m_arraySize;
|
||||
if (hasMipMaps) {
|
||||
for (int level = 0; level != mipLevelCount; ++level) {
|
||||
|
|
@ -5125,10 +5235,13 @@ bool QGles2Texture::create()
|
|||
// Must be specified with immutable storage functions otherwise
|
||||
// bindImageTexture may fail. Also, the internal format must be a
|
||||
// sized format here.
|
||||
if (is3D || isArray)
|
||||
if (is1D && !isArray)
|
||||
rhiD->glTexStorage1D(target, mipLevelCount, glsizedintformat, size.width());
|
||||
else if (!is1D && (is3D || isArray))
|
||||
rhiD->f->glTexStorage3D(target, mipLevelCount, glsizedintformat, size.width(), size.height(), is3D ? m_depth : m_arraySize);
|
||||
else
|
||||
rhiD->f->glTexStorage2D(target, mipLevelCount, glsizedintformat, size.width(), size.height());
|
||||
rhiD->f->glTexStorage2D(target, mipLevelCount, glsizedintformat, size.width(),
|
||||
is1D ? m_arraySize : size.height());
|
||||
}
|
||||
specified = true;
|
||||
} else {
|
||||
|
|
@ -5342,6 +5455,10 @@ bool QGles2TextureRenderTarget::create()
|
|||
if (texD->flags().testFlag(QRhiTexture::ThreeDimensional) || texD->flags().testFlag(QRhiTexture::TextureArray)) {
|
||||
rhiD->f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), texD->texture,
|
||||
colorAtt.level(), colorAtt.layer());
|
||||
} else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
|
||||
rhiD->glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex),
|
||||
texD->target + uint(colorAtt.layer()), texD->texture,
|
||||
colorAtt.level());
|
||||
} else {
|
||||
const GLenum faceTargetBase = texD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
|
||||
rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()),
|
||||
|
|
|
|||
|
|
@ -896,6 +896,20 @@ public:
|
|||
mutable bool needsMakeCurrentDueToSwap = false;
|
||||
QOpenGLExtensions *f = nullptr;
|
||||
void (QOPENGLF_APIENTRYP glPolygonMode) (GLenum, GLenum) = nullptr;
|
||||
void(QOPENGLF_APIENTRYP glTexImage1D)(GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum,
|
||||
const void *) = nullptr;
|
||||
void(QOPENGLF_APIENTRYP glTexStorage1D)(GLenum, GLint, GLenum, GLsizei) = nullptr;
|
||||
void(QOPENGLF_APIENTRYP glTexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum, GLenum,
|
||||
const GLvoid *) = nullptr;
|
||||
void(QOPENGLF_APIENTRYP glCopyTexSubImage1D)(GLenum, GLint, GLint, GLint, GLint,
|
||||
GLsizei) = nullptr;
|
||||
void(QOPENGLF_APIENTRYP glCompressedTexImage1D)(GLenum, GLint, GLenum, GLsizei, GLint, GLsizei,
|
||||
const GLvoid *) = nullptr;
|
||||
void(QOPENGLF_APIENTRYP glCompressedTexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum,
|
||||
GLsizei, const GLvoid *) = nullptr;
|
||||
void(QOPENGLF_APIENTRYP glFramebufferTexture1D)(GLenum, GLenum, GLenum, GLuint,
|
||||
GLint) = nullptr;
|
||||
|
||||
uint vao = 0;
|
||||
struct Caps {
|
||||
Caps()
|
||||
|
|
@ -945,7 +959,8 @@ public:
|
|||
programBinary(false),
|
||||
texture3D(false),
|
||||
tessellation(false),
|
||||
geometryShader(false)
|
||||
geometryShader(false),
|
||||
texture1D(false)
|
||||
{ }
|
||||
int ctxMajor;
|
||||
int ctxMinor;
|
||||
|
|
@ -996,6 +1011,7 @@ public:
|
|||
uint texture3D : 1;
|
||||
uint tessellation : 1;
|
||||
uint geometryShader : 1;
|
||||
uint texture1D : 1;
|
||||
} caps;
|
||||
QGles2SwapChain *currentSwapChain = nullptr;
|
||||
QSet<GLint> supportedCompressedFormats;
|
||||
|
|
|
|||
|
|
@ -772,6 +772,10 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
|
|||
return false;
|
||||
case QRhi::NonFillPolygonMode:
|
||||
return true;
|
||||
case QRhi::OneDimensionalTextures:
|
||||
return true;
|
||||
case QRhi::OneDimensionalTextureMipmaps:
|
||||
return false;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
return false;
|
||||
|
|
@ -3414,11 +3418,14 @@ bool QMetalTexture::prepareCreate(QSize *adjustedSize)
|
|||
if (d->tex)
|
||||
destroy();
|
||||
|
||||
const QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
|
||||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
|
||||
const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
|
||||
: (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
|
||||
|
||||
QRHI_RES_RHI(QRhiMetal);
|
||||
d->format = toMetalTextureFormat(m_format, m_flags, rhiD);
|
||||
|
|
@ -3446,6 +3453,14 @@ bool QMetalTexture::prepareCreate(QSize *adjustedSize)
|
|||
qWarning("Texture cannot be both array and 3D");
|
||||
return false;
|
||||
}
|
||||
if (is1D && is3D) {
|
||||
qWarning("Texture cannot be both 1D and 3D");
|
||||
return false;
|
||||
}
|
||||
if (is1D && isCube) {
|
||||
qWarning("Texture cannot be both 1D and cube");
|
||||
return false;
|
||||
}
|
||||
m_depth = qMax(1, m_depth);
|
||||
if (m_depth > 1 && !is3D) {
|
||||
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
|
||||
|
|
@ -3478,10 +3493,13 @@ bool QMetalTexture::create()
|
|||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
if (isCube) {
|
||||
desc.textureType = MTLTextureTypeCube;
|
||||
} else if (is3D) {
|
||||
desc.textureType = MTLTextureType3D;
|
||||
} else if (is1D) {
|
||||
desc.textureType = isArray ? MTLTextureType1DArray : MTLTextureType1D;
|
||||
} else if (isArray) {
|
||||
#ifdef Q_OS_IOS
|
||||
if (samples > 1) {
|
||||
|
|
|
|||
|
|
@ -661,7 +661,9 @@ bool QNullTexture::create()
|
|||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
||||
QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
|
||||
const bool is1D = m_flags.testFlags(OneDimensional);
|
||||
QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
|
||||
: (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
|
||||
m_depth = qMax(1, m_depth);
|
||||
const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
|
||||
m_arraySize = qMax(0, m_arraySize);
|
||||
|
|
|
|||
|
|
@ -2939,6 +2939,7 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
|
|||
qsizetype imageSizeBytes = 0;
|
||||
const void *src = nullptr;
|
||||
const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
|
||||
const bool is1D = texD->m_flags.testFlag(QRhiTexture::OneDimensional);
|
||||
|
||||
VkBufferImageCopy copyInfo = {};
|
||||
copyInfo.bufferOffset = *curOfs;
|
||||
|
|
@ -2949,6 +2950,8 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
|
|||
copyInfo.imageExtent.depth = 1;
|
||||
if (is3D)
|
||||
copyInfo.imageOffset.z = uint32_t(layer);
|
||||
if (is1D)
|
||||
copyInfo.imageOffset.y = uint32_t(layer);
|
||||
|
||||
const QByteArray rawData = subresDesc.data();
|
||||
const QPoint dp = subresDesc.destinationTopLeft();
|
||||
|
|
@ -4257,6 +4260,10 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
|
|||
return true;
|
||||
case QRhi::NonFillPolygonMode:
|
||||
return caps.nonFillPolygonMode;
|
||||
case QRhi::OneDimensionalTextures:
|
||||
return true;
|
||||
case QRhi::OneDimensionalTextureMipmaps:
|
||||
return true;
|
||||
default:
|
||||
Q_UNREACHABLE_RETURN(false);
|
||||
}
|
||||
|
|
@ -5874,12 +5881,15 @@ bool QVkTexture::prepareCreate(QSize *adjustedSize)
|
|||
return false;
|
||||
}
|
||||
|
||||
const QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
|
||||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
||||
|
||||
const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
|
||||
: (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
|
||||
|
||||
mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
|
||||
const int maxLevels = QRhi::MAX_MIP_LEVELS;
|
||||
if (mipLevelCount > maxLevels) {
|
||||
|
|
@ -5909,6 +5919,14 @@ bool QVkTexture::prepareCreate(QSize *adjustedSize)
|
|||
qWarning("Texture cannot be both array and 3D");
|
||||
return false;
|
||||
}
|
||||
if (isCube && is1D) {
|
||||
qWarning("Texture cannot be both cube and 1D");
|
||||
return false;
|
||||
}
|
||||
if (is1D && is3D) {
|
||||
qWarning("Texture cannot be both 1D and 3D");
|
||||
return false;
|
||||
}
|
||||
m_depth = qMax(1, m_depth);
|
||||
if (m_depth > 1 && !is3D) {
|
||||
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
|
||||
|
|
@ -5942,13 +5960,16 @@ bool QVkTexture::finishCreate()
|
|||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
|
||||
VkImageViewCreateInfo viewInfo = {};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = image;
|
||||
viewInfo.viewType = isCube ? VK_IMAGE_VIEW_TYPE_CUBE
|
||||
: (is3D ? VK_IMAGE_VIEW_TYPE_3D
|
||||
: (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D));
|
||||
viewInfo.viewType = isCube
|
||||
? VK_IMAGE_VIEW_TYPE_CUBE
|
||||
: (is3D ? VK_IMAGE_VIEW_TYPE_3D
|
||||
: (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
|
||||
: (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
|
||||
viewInfo.format = vkformat;
|
||||
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
|
|
@ -5987,6 +6008,7 @@ bool QVkTexture::create()
|
|||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
|
||||
VkImageCreateInfo imageInfo = {};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
|
|
@ -6009,7 +6031,7 @@ bool QVkTexture::create()
|
|||
#endif
|
||||
}
|
||||
|
||||
imageInfo.imageType = is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
|
||||
imageInfo.imageType = is1D ? VK_IMAGE_TYPE_1D : is3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D;
|
||||
imageInfo.format = vkformat;
|
||||
imageInfo.extent.width = uint32_t(size.width());
|
||||
imageInfo.extent.height = uint32_t(size.height());
|
||||
|
|
@ -6097,13 +6119,16 @@ VkImageView QVkTexture::imageViewForLevel(int level)
|
|||
const bool isCube = m_flags.testFlag(CubeMap);
|
||||
const bool isArray = m_flags.testFlag(TextureArray);
|
||||
const bool is3D = m_flags.testFlag(ThreeDimensional);
|
||||
const bool is1D = m_flags.testFlag(OneDimensional);
|
||||
|
||||
VkImageViewCreateInfo viewInfo = {};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = image;
|
||||
viewInfo.viewType = isCube ? VK_IMAGE_VIEW_TYPE_CUBE
|
||||
: (is3D ? VK_IMAGE_VIEW_TYPE_3D
|
||||
: (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D));
|
||||
viewInfo.viewType = isCube
|
||||
? VK_IMAGE_VIEW_TYPE_CUBE
|
||||
: (is3D ? VK_IMAGE_VIEW_TYPE_3D
|
||||
: (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
|
||||
: (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
|
||||
viewInfo.format = vkformat;
|
||||
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
|
|
@ -6487,7 +6512,9 @@ bool QVkTextureRenderTarget::create()
|
|||
VkImageViewCreateInfo viewInfo = {};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = texD->image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.viewType = texD->flags().testFlag(QRhiTexture::OneDimensional)
|
||||
? VK_IMAGE_VIEW_TYPE_1D
|
||||
: VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = texD->vkformat;
|
||||
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,8 @@ private slots:
|
|||
void renderbufferImportOpenGL();
|
||||
void threeDimTexture_data();
|
||||
void threeDimTexture();
|
||||
void oneDimTexture_data();
|
||||
void oneDimTexture();
|
||||
void leakedResourceDestroy_data();
|
||||
void leakedResourceDestroy();
|
||||
|
||||
|
|
@ -4677,6 +4679,514 @@ void tst_QRhi::threeDimTexture()
|
|||
QVERIFY(imageRGBAEquals(result, referenceImage));
|
||||
}
|
||||
}
|
||||
void tst_QRhi::oneDimTexture_data()
|
||||
{
|
||||
rhiTestData();
|
||||
}
|
||||
|
||||
void tst_QRhi::oneDimTexture()
|
||||
{
|
||||
QFETCH(QRhi::Implementation, impl);
|
||||
QFETCH(QRhiInitParams *, initParams);
|
||||
|
||||
QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams));
|
||||
if (!rhi)
|
||||
QSKIP("QRhi could not be created, skipping testing 1D textures");
|
||||
|
||||
if (!rhi->isFeatureSupported(QRhi::OneDimensionalTextures))
|
||||
QSKIP("Skipping testing 1D textures because they are reported as unsupported");
|
||||
|
||||
const int WIDTH = 512;
|
||||
const int LAYERS = 128;
|
||||
|
||||
{
|
||||
QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, WIDTH, 0, 0));
|
||||
QVERIFY(texture->create());
|
||||
|
||||
QVERIFY(texture->flags().testFlag(QRhiTexture::Flag::OneDimensional));
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
QImage img(WIDTH, 1, QImage::Format_RGBA8888);
|
||||
img.fill(QColor::fromRgb(255, 0, 0));
|
||||
|
||||
QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(texture.data(), upload);
|
||||
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
}
|
||||
|
||||
{
|
||||
QScopedPointer<QRhiTexture> texture(
|
||||
rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0)));
|
||||
QVERIFY(texture->create());
|
||||
|
||||
QVERIFY(texture->flags().testFlag(QRhiTexture::Flag::OneDimensional));
|
||||
QVERIFY(texture->flags().testFlag(QRhiTexture::Flag::TextureArray));
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
for (int i = 0; i < LAYERS; ++i) {
|
||||
QImage img(WIDTH, 1, QImage::Format_RGBA8888);
|
||||
img.fill(QColor::fromRgb(i * 2, 0, 0));
|
||||
QRhiTextureUploadEntry layerUpload(i, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(texture.data(), layerUpload);
|
||||
}
|
||||
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
}
|
||||
|
||||
// Copy from 2D texture to 1D texture
|
||||
{
|
||||
const int WIDTH = 256;
|
||||
const int HEIGHT = 256;
|
||||
|
||||
QScopedPointer<QRhiTexture> srcTexture(rhi->newTexture(
|
||||
QRhiTexture::RGBA8, WIDTH, HEIGHT, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
|
||||
QVERIFY(srcTexture->create());
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
QImage img(WIDTH, HEIGHT, QImage::Format_RGBA8888);
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
for (int y = 0; y < HEIGHT; ++y) {
|
||||
img.setPixelColor(x, y, QColor::fromRgb(x, y, 0));
|
||||
}
|
||||
}
|
||||
QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(srcTexture.data(), upload);
|
||||
|
||||
QScopedPointer<QRhiTexture> dstTexture(rhi->newTexture(
|
||||
QRhiTexture::RGBA8, WIDTH, 0, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
|
||||
QVERIFY(dstTexture->create());
|
||||
|
||||
QRhiTextureCopyDescription copy;
|
||||
copy.setPixelSize(QSize(WIDTH / 2, 1));
|
||||
copy.setDestinationTopLeft(QPoint(WIDTH / 2, 0));
|
||||
copy.setSourceTopLeft(QPoint(33, 67));
|
||||
batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
|
||||
|
||||
copy.setDestinationTopLeft(QPoint(0, 0));
|
||||
copy.setSourceTopLeft(QPoint(99, 12));
|
||||
batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
|
||||
|
||||
QRhiReadbackResult readResult;
|
||||
QImage result;
|
||||
readResult.completed = [&readResult, &result] {
|
||||
result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
|
||||
readResult.pixelSize.width(), readResult.pixelSize.height(),
|
||||
QImage::Format_RGBA8888);
|
||||
};
|
||||
|
||||
QRhiReadbackDescription readbackDescription(dstTexture.data());
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
QImage referenceImage(WIDTH, 1, result.format());
|
||||
for (int i = 0; i < WIDTH / 2; ++i) {
|
||||
referenceImage.setPixelColor(i, 0, img.pixelColor(99 + i, 12));
|
||||
referenceImage.setPixelColor(WIDTH / 2 + i, 0, img.pixelColor(33 + i, 67));
|
||||
}
|
||||
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage));
|
||||
}
|
||||
|
||||
// Copy from 2D texture to 1D texture array
|
||||
{
|
||||
const int WIDTH = 256;
|
||||
const int HEIGHT = 256;
|
||||
const int LAYERS = 64;
|
||||
|
||||
QScopedPointer<QRhiTexture> srcTexture(rhi->newTexture(
|
||||
QRhiTexture::RGBA8, WIDTH, HEIGHT, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
|
||||
QVERIFY(srcTexture->create());
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
QImage img(WIDTH, HEIGHT, QImage::Format_RGBA8888);
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
for (int y = 0; y < HEIGHT; ++y) {
|
||||
img.setPixelColor(x, y, QColor::fromRgb(x, y, 0));
|
||||
}
|
||||
}
|
||||
QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(srcTexture.data(), upload);
|
||||
|
||||
QScopedPointer<QRhiTexture> dstTexture(
|
||||
rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
|
||||
QRhiTexture::Flag::UsedAsTransferSource));
|
||||
QVERIFY(dstTexture->create());
|
||||
|
||||
QRhiTextureCopyDescription copy;
|
||||
copy.setPixelSize(QSize(WIDTH / 2, 1));
|
||||
copy.setDestinationTopLeft(QPoint(WIDTH / 2, 0));
|
||||
copy.setSourceTopLeft(QPoint(33, 67));
|
||||
copy.setDestinationLayer(12);
|
||||
batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
|
||||
|
||||
copy.setDestinationTopLeft(QPoint(0, 0));
|
||||
copy.setSourceTopLeft(QPoint(99, 12));
|
||||
batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
|
||||
|
||||
QRhiReadbackResult readResult;
|
||||
QImage result;
|
||||
readResult.completed = [&readResult, &result] {
|
||||
result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
|
||||
readResult.pixelSize.width(), readResult.pixelSize.height(),
|
||||
QImage::Format_RGBA8888);
|
||||
};
|
||||
|
||||
QRhiReadbackDescription readbackDescription(dstTexture.data());
|
||||
readbackDescription.setLayer(12);
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
QImage referenceImage(WIDTH, 1, result.format());
|
||||
for (int i = 0; i < WIDTH / 2; ++i) {
|
||||
referenceImage.setPixelColor(i, 0, img.pixelColor(99 + i, 12));
|
||||
referenceImage.setPixelColor(WIDTH / 2 + i, 0, img.pixelColor(33 + i, 67));
|
||||
}
|
||||
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage));
|
||||
}
|
||||
|
||||
// Copy from 1D texture array to 1D texture
|
||||
{
|
||||
const int WIDTH = 256;
|
||||
const int LAYERS = 256;
|
||||
|
||||
QScopedPointer<QRhiTexture> srcTexture(
|
||||
rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
|
||||
QRhiTexture::Flag::UsedAsTransferSource));
|
||||
QVERIFY(srcTexture->create());
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
for (int y = 0; y < LAYERS; ++y) {
|
||||
QImage img(WIDTH, 1, QImage::Format_RGBA8888);
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
img.setPixelColor(x, 0, QColor::fromRgb(x, y, 0));
|
||||
}
|
||||
QRhiTextureUploadEntry upload(y, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(srcTexture.data(), upload);
|
||||
}
|
||||
|
||||
QScopedPointer<QRhiTexture> dstTexture(rhi->newTexture(
|
||||
QRhiTexture::RGBA8, WIDTH, 0, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
|
||||
QVERIFY(dstTexture->create());
|
||||
|
||||
QRhiTextureCopyDescription copy;
|
||||
copy.setPixelSize(QSize(WIDTH / 2, 1));
|
||||
copy.setDestinationTopLeft(QPoint(WIDTH / 2, 0));
|
||||
copy.setSourceLayer(67);
|
||||
copy.setSourceTopLeft(QPoint(33, 0));
|
||||
batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
|
||||
|
||||
copy.setDestinationTopLeft(QPoint(0, 0));
|
||||
copy.setSourceLayer(12);
|
||||
copy.setSourceTopLeft(QPoint(99, 0));
|
||||
batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
|
||||
|
||||
QRhiReadbackResult readResult;
|
||||
QImage result;
|
||||
readResult.completed = [&readResult, &result] {
|
||||
result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
|
||||
readResult.pixelSize.width(), readResult.pixelSize.height(),
|
||||
QImage::Format_RGBA8888);
|
||||
};
|
||||
|
||||
QRhiReadbackDescription readbackDescription(dstTexture.data());
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
QImage referenceImage(WIDTH, 1, result.format());
|
||||
for (int i = 0; i < WIDTH / 2; ++i) {
|
||||
referenceImage.setPixelColor(i, 0, QColor::fromRgb(99 + i, 12, 0));
|
||||
referenceImage.setPixelColor(WIDTH / 2 + i, 0, QColor::fromRgb(33 + i, 67, 0));
|
||||
}
|
||||
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage));
|
||||
}
|
||||
|
||||
// Copy from 1D texture to 1D texture array
|
||||
{
|
||||
const int WIDTH = 256;
|
||||
const int LAYERS = 256;
|
||||
|
||||
QScopedPointer<QRhiTexture> srcTexture(rhi->newTexture(
|
||||
QRhiTexture::RGBA8, WIDTH, 0, 0, 1, QRhiTexture::Flag::UsedAsTransferSource));
|
||||
QVERIFY(srcTexture->create());
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
QImage img(WIDTH, 1, QImage::Format_RGBA8888);
|
||||
for (int x = 0; x < WIDTH; ++x) {
|
||||
img.setPixelColor(x, 0, QColor::fromRgb(x, 0, 0));
|
||||
}
|
||||
QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(srcTexture.data(), upload);
|
||||
|
||||
QScopedPointer<QRhiTexture> dstTexture(
|
||||
rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
|
||||
QRhiTexture::Flag::UsedAsTransferSource));
|
||||
QVERIFY(dstTexture->create());
|
||||
|
||||
QRhiTextureCopyDescription copy;
|
||||
copy.setPixelSize(QSize(WIDTH / 2, 1));
|
||||
copy.setDestinationTopLeft(QPoint(WIDTH / 2, 0));
|
||||
copy.setDestinationLayer(67);
|
||||
copy.setSourceTopLeft(QPoint(33, 0));
|
||||
batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
|
||||
|
||||
copy.setDestinationTopLeft(QPoint(0, 0));
|
||||
copy.setSourceTopLeft(QPoint(99, 0));
|
||||
batch->copyTexture(dstTexture.data(), srcTexture.data(), copy);
|
||||
|
||||
QRhiReadbackResult readResult;
|
||||
QImage result;
|
||||
readResult.completed = [&readResult, &result] {
|
||||
result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
|
||||
readResult.pixelSize.width(), readResult.pixelSize.height(),
|
||||
QImage::Format_RGBA8888);
|
||||
};
|
||||
|
||||
QRhiReadbackDescription readbackDescription(dstTexture.data());
|
||||
readbackDescription.setLayer(67);
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
QImage referenceImage(WIDTH, 1, result.format());
|
||||
for (int i = 0; i < WIDTH / 2; ++i) {
|
||||
referenceImage.setPixelColor(i, 0, QColor::fromRgb(99 + i, 0, 0));
|
||||
referenceImage.setPixelColor(WIDTH / 2 + i, 0, QColor::fromRgb(33 + i, 0, 0));
|
||||
}
|
||||
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage));
|
||||
}
|
||||
|
||||
// mipmaps and 1D render target
|
||||
if (!rhi->isFeatureSupported(QRhi::OneDimensionalTextureMipmaps))
|
||||
QSKIP("Skipping testing 1D texture mipmaps and 1D render target because they are reported "
|
||||
"as unsupported");
|
||||
|
||||
{
|
||||
QScopedPointer<QRhiTexture> texture(
|
||||
rhi->newTexture(QRhiTexture::RGBA8, WIDTH, 0, 0, 1,
|
||||
QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
|
||||
QVERIFY(texture->create());
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
QImage img(WIDTH, 1, QImage::Format_RGBA8888);
|
||||
img.fill(QColor::fromRgb(128, 0, 0));
|
||||
QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(texture.data(), upload);
|
||||
|
||||
batch->generateMips(texture.data());
|
||||
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
|
||||
// read back level 1 (256x1, #800000ff)
|
||||
batch = rhi->nextResourceUpdateBatch();
|
||||
QRhiReadbackResult readResult;
|
||||
QImage result;
|
||||
readResult.completed = [&readResult, &result] {
|
||||
result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
|
||||
readResult.pixelSize.width(), readResult.pixelSize.height(),
|
||||
QImage::Format_RGBA8888);
|
||||
};
|
||||
QRhiReadbackDescription readbackDescription(texture.data());
|
||||
readbackDescription.setLevel(1);
|
||||
readbackDescription.setLayer(0);
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
QImage referenceImage(WIDTH / 2, 1, result.format());
|
||||
referenceImage.fill(QColor::fromRgb(128, 0, 0));
|
||||
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage, 2));
|
||||
}
|
||||
|
||||
{
|
||||
QScopedPointer<QRhiTexture> texture(
|
||||
rhi->newTextureArray(QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
|
||||
QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips));
|
||||
QVERIFY(texture->create());
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
for (int i = 0; i < LAYERS; ++i) {
|
||||
QImage img(WIDTH, 1, QImage::Format_RGBA8888);
|
||||
img.fill(QColor::fromRgb(i * 2, 0, 0));
|
||||
QRhiTextureUploadEntry sliceUpload(i, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(texture.data(), sliceUpload);
|
||||
}
|
||||
|
||||
batch->generateMips(texture.data());
|
||||
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
|
||||
// read back slice 63 of level 1 (256x1, #7E0000FF)
|
||||
batch = rhi->nextResourceUpdateBatch();
|
||||
QRhiReadbackResult readResult;
|
||||
QImage result;
|
||||
readResult.completed = [&readResult, &result] {
|
||||
result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
|
||||
readResult.pixelSize.width(), readResult.pixelSize.height(),
|
||||
QImage::Format_RGBA8888);
|
||||
};
|
||||
QRhiReadbackDescription readbackDescription(texture.data());
|
||||
readbackDescription.setLevel(1);
|
||||
readbackDescription.setLayer(63);
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
QImage referenceImage(WIDTH / 2, 1, result.format());
|
||||
referenceImage.fill(QColor::fromRgb(126, 0, 0));
|
||||
|
||||
// Now restrict the test a bit. The Null QRhi backend has broken support for
|
||||
// mipmap generation of 1D texture arrays.
|
||||
if (impl != QRhi::Null)
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage, 2));
|
||||
}
|
||||
|
||||
// 1D texture render target
|
||||
// NB with Vulkan we require Vulkan 1.1 for this to work.
|
||||
// Metal does not allow 1D texture render targets
|
||||
{
|
||||
QScopedPointer<QRhiTexture> texture(
|
||||
rhi->newTexture(QRhiTexture::RGBA8, WIDTH, 0, 0, 1,
|
||||
QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
|
||||
QVERIFY(texture->create());
|
||||
|
||||
QRhiColorAttachment att(texture.data());
|
||||
QRhiTextureRenderTargetDescription rtDesc(att);
|
||||
QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
|
||||
QScopedPointer<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
|
||||
rt->setRenderPassDescriptor(rp.data());
|
||||
QVERIFY(rt->create());
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
QImage img(WIDTH, 1, QImage::Format_RGBA8888);
|
||||
img.fill(QColor::fromRgb(128, 0, 0));
|
||||
QRhiTextureUploadEntry upload(0, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(texture.data(), upload);
|
||||
|
||||
QRhiCommandBuffer *cb = nullptr;
|
||||
QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
|
||||
QVERIFY(cb);
|
||||
cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, batch);
|
||||
// texture is now blue
|
||||
cb->endPass();
|
||||
rhi->endOffscreenFrame();
|
||||
|
||||
// read back texture (blue)
|
||||
batch = rhi->nextResourceUpdateBatch();
|
||||
QRhiReadbackResult readResult;
|
||||
QImage result;
|
||||
readResult.completed = [&readResult, &result] {
|
||||
result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
|
||||
readResult.pixelSize.width(), readResult.pixelSize.height(),
|
||||
QImage::Format_RGBA8888);
|
||||
};
|
||||
QRhiReadbackDescription readbackDescription(texture.data());
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
QImage referenceImage(WIDTH, 1, result.format());
|
||||
referenceImage.fill(QColor::fromRgbF(0.0f, 0.0f, 1.0f));
|
||||
// the Null backend does not render so skip the verification for that
|
||||
if (impl != QRhi::Null)
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage));
|
||||
}
|
||||
|
||||
// 1D array texture render target (one slice)
|
||||
// NB with Vulkan we require Vulkan 1.1 for this to work.
|
||||
// Metal does not allow 1D texture render targets
|
||||
{
|
||||
const int SLICE = 23;
|
||||
QScopedPointer<QRhiTexture> texture(rhi->newTextureArray(
|
||||
QRhiTexture::RGBA8, LAYERS, QSize(WIDTH, 0), 1,
|
||||
QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
|
||||
QVERIFY(texture->create());
|
||||
|
||||
QRhiColorAttachment att(texture.data());
|
||||
att.setLayer(SLICE);
|
||||
QRhiTextureRenderTargetDescription rtDesc(att);
|
||||
QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
|
||||
QScopedPointer<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
|
||||
rt->setRenderPassDescriptor(rp.data());
|
||||
QVERIFY(rt->create());
|
||||
|
||||
QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
|
||||
QVERIFY(batch);
|
||||
|
||||
for (int i = 0; i < LAYERS; ++i) {
|
||||
QImage img(WIDTH, 1, QImage::Format_RGBA8888);
|
||||
img.fill(QColor::fromRgb(i * 2, 0, 0));
|
||||
QRhiTextureUploadEntry sliceUpload(i, 0, QRhiTextureSubresourceUploadDescription(img));
|
||||
batch->uploadTexture(texture.data(), sliceUpload);
|
||||
}
|
||||
|
||||
QRhiCommandBuffer *cb = nullptr;
|
||||
QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
|
||||
QVERIFY(cb);
|
||||
cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, batch);
|
||||
// slice 23 is now blue
|
||||
cb->endPass();
|
||||
rhi->endOffscreenFrame();
|
||||
|
||||
// read back slice 23 (blue)
|
||||
batch = rhi->nextResourceUpdateBatch();
|
||||
QRhiReadbackResult readResult;
|
||||
QImage result;
|
||||
readResult.completed = [&readResult, &result] {
|
||||
result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
|
||||
readResult.pixelSize.width(), readResult.pixelSize.height(),
|
||||
QImage::Format_RGBA8888);
|
||||
};
|
||||
QRhiReadbackDescription readbackDescription(texture.data());
|
||||
readbackDescription.setLayer(23);
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
QImage referenceImage(WIDTH, 1, result.format());
|
||||
referenceImage.fill(QColor::fromRgbF(0.0f, 0.0f, 1.0f));
|
||||
// the Null backend does not render so skip the verification for that
|
||||
if (impl != QRhi::Null)
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage));
|
||||
|
||||
// read back slice 0 (black)
|
||||
batch = rhi->nextResourceUpdateBatch();
|
||||
result = QImage();
|
||||
readbackDescription.setLayer(0);
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
referenceImage.fill(QColor::fromRgbF(0.0f, 0.0f, 0.0f));
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage));
|
||||
|
||||
// read back slice 127 (almost red)
|
||||
batch = rhi->nextResourceUpdateBatch();
|
||||
result = QImage();
|
||||
readbackDescription.setLayer(127);
|
||||
batch->readBackTexture(readbackDescription, &readResult);
|
||||
QVERIFY(submitResourceUpdates(rhi.data(), batch));
|
||||
QVERIFY(!result.isNull());
|
||||
referenceImage.fill(QColor::fromRgb(254, 0, 0));
|
||||
QVERIFY(imageRGBAEquals(result, referenceImage));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QRhi::leakedResourceDestroy_data()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ add_subdirectory(tessellation)
|
|||
add_subdirectory(geometryshader)
|
||||
add_subdirectory(stenciloutline)
|
||||
add_subdirectory(stereo)
|
||||
add_subdirectory(tex1d)
|
||||
if(QT_FEATURE_widgets)
|
||||
add_subdirectory(rhiwidget)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
qt_internal_add_manual_test(tex1d
|
||||
GUI
|
||||
SOURCES
|
||||
tex1d.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
||||
set(tex1d_resource_files
|
||||
"texture1d.vert.qsb"
|
||||
"texture1d.frag.qsb"
|
||||
)
|
||||
|
||||
qt_internal_add_resource(tex1d "tex1d"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${tex1d_resource_files}
|
||||
)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
qsb --glsl "300 es,150" --hlsl 50 --msl 12 -c texture1d.vert -o texture1d.vert.qsb
|
||||
qsb --glsl "300 es,150" --hlsl 50 --msl 12 -c texture1d.frag -o texture1d.frag.qsb
|
||||
|
|
@ -0,0 +1,625 @@
|
|||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "../shared/examplefw.h"
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
#include <functional>
|
||||
|
||||
static float quadVertexData[] = { // Y up, CCW
|
||||
-0.5f, 0.5f, 0.0f, 0.0f, -0.5f, -0.5f, 0.0f, 1.0f,
|
||||
0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 1.0f, 0.0f
|
||||
};
|
||||
|
||||
static quint16 quadIndexData[] = { 0, 1, 2, 0, 2, 3 };
|
||||
|
||||
struct
|
||||
{
|
||||
QList<QRhiResource *> releasePool;
|
||||
QRhiResourceUpdateBatch *initialUpdates = nullptr;
|
||||
|
||||
QRhiBuffer *vertexBuffer = nullptr;
|
||||
QRhiBuffer *indexBuffer = nullptr;
|
||||
QRhiBuffer *uniformBuffer = nullptr;
|
||||
QRhiGraphicsPipeline *ps = nullptr;
|
||||
QRhiShaderResourceBindings *srb = nullptr;
|
||||
int index = 0;
|
||||
} d;
|
||||
|
||||
void readBackCompleted(QRhiReadbackResult *result, const QByteArray &expected)
|
||||
{
|
||||
if (result->data != expected) {
|
||||
qFatal("texture readback data did not match expected values");
|
||||
}
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
void Window::customInit()
|
||||
{
|
||||
if (!m_r->isFeatureSupported(QRhi::Feature::OneDimensionalTextures))
|
||||
qFatal("1D textures are not supported");
|
||||
|
||||
const bool mipmaps = m_r->isFeatureSupported(QRhi::Feature::OneDimensionalTextureMipmaps);
|
||||
|
||||
d.initialUpdates = m_r->nextResourceUpdateBatch();
|
||||
|
||||
QRhiTexture *texture = nullptr;
|
||||
QRhiReadbackResult *readbackResult = nullptr;
|
||||
QRhiReadbackDescription readbackDescription;
|
||||
QByteArray data;
|
||||
|
||||
QList<QRhiShaderResourceBinding> shaderResouceBindings;
|
||||
|
||||
//
|
||||
// Create vertex buffer
|
||||
//
|
||||
d.vertexBuffer =
|
||||
m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(quadVertexData));
|
||||
d.vertexBuffer->create();
|
||||
d.releasePool << d.vertexBuffer;
|
||||
|
||||
d.initialUpdates->uploadStaticBuffer(d.vertexBuffer, 0, sizeof(quadVertexData), quadVertexData);
|
||||
|
||||
//
|
||||
// Create index buffer
|
||||
//
|
||||
d.indexBuffer =
|
||||
m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(quadIndexData));
|
||||
d.indexBuffer->create();
|
||||
d.releasePool << d.indexBuffer;
|
||||
|
||||
d.initialUpdates->uploadStaticBuffer(d.indexBuffer, quadIndexData);
|
||||
|
||||
//
|
||||
// Create uniform buffer
|
||||
//
|
||||
d.uniformBuffer =
|
||||
m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, m_r->ubufAligned(4));
|
||||
d.uniformBuffer->create();
|
||||
d.releasePool << d.uniformBuffer;
|
||||
|
||||
shaderResouceBindings.append(QRhiShaderResourceBinding::uniformBuffer(
|
||||
0, QRhiShaderResourceBinding::StageFlag::FragmentStage, d.uniformBuffer, 0, 4));
|
||||
|
||||
//
|
||||
// Create samplers
|
||||
//
|
||||
QRhiSampler *samplerNearest = m_r->newSampler(
|
||||
QRhiSampler::Filter::Nearest, QRhiSampler::Filter::Nearest,
|
||||
QRhiSampler::Filter::Nearest, QRhiSampler::AddressMode::ClampToEdge,
|
||||
QRhiSampler::AddressMode::ClampToEdge, QRhiSampler::AddressMode::ClampToEdge);
|
||||
d.releasePool << samplerNearest;
|
||||
samplerNearest->create();
|
||||
|
||||
QRhiSampler *samplerNone = m_r->newSampler(
|
||||
QRhiSampler::Filter::Nearest, QRhiSampler::Filter::Nearest, QRhiSampler::Filter::None,
|
||||
QRhiSampler::AddressMode::ClampToEdge, QRhiSampler::AddressMode::ClampToEdge,
|
||||
QRhiSampler::AddressMode::ClampToEdge);
|
||||
d.releasePool << samplerNone;
|
||||
samplerNone->create();
|
||||
|
||||
//
|
||||
// 1D texture with generated mipmaps. Contains grey colormap
|
||||
//
|
||||
texture = m_r->newTexture(QRhiTexture::Format::RGBA8, 8, 0, 0, 1,
|
||||
QRhiTexture::Flag::OneDimensional
|
||||
| QRhiTexture::Flag::UsedAsTransferSource
|
||||
| (mipmaps ? (QRhiTexture::Flag::MipMapped
|
||||
| QRhiTexture::Flag::UsedWithGenerateMips)
|
||||
: QRhiTexture::Flag(0)));
|
||||
d.releasePool << texture;
|
||||
texture->create();
|
||||
|
||||
shaderResouceBindings.append(QRhiShaderResourceBinding::sampledTexture(
|
||||
1, QRhiShaderResourceBinding::FragmentStage, texture,
|
||||
texture->flags().testFlag(QRhiTexture::Flag::MipMapped) ? samplerNearest
|
||||
: samplerNone));
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
data.append(char(i) * 32);
|
||||
data.append(char(i) * 32);
|
||||
data.append(char(i) * 32);
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture, QRhiTextureUploadEntry(0, 0, QRhiTextureSubresourceUploadDescription(data)));
|
||||
if (mipmaps)
|
||||
d.initialUpdates->generateMips(texture);
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(0);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
//
|
||||
// 1D texture array with generated mipmaps. layer 0 contains red colormap, layer 1 contains
|
||||
// green colormap
|
||||
//
|
||||
texture =
|
||||
m_r->newTextureArray(QRhiTexture::RGBA8, 2, QSize(8, 0), 1,
|
||||
QRhiTexture::Flag::TextureArray | QRhiTexture::Flag::OneDimensional
|
||||
| QRhiTexture::Flag::UsedAsTransferSource
|
||||
| (mipmaps ? (QRhiTexture::Flag::MipMapped
|
||||
| QRhiTexture::Flag::UsedWithGenerateMips)
|
||||
: QRhiTexture::Flag(0)));
|
||||
d.releasePool << texture;
|
||||
texture->create();
|
||||
|
||||
shaderResouceBindings.append(QRhiShaderResourceBinding::sampledTexture(
|
||||
2, QRhiShaderResourceBinding::FragmentStage, texture,
|
||||
texture->flags().testFlag(QRhiTexture::Flag::MipMapped) ? samplerNearest
|
||||
: samplerNone));
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
data.append(char(i * 32));
|
||||
data.append(char(0));
|
||||
data.append(char(0));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture, QRhiTextureUploadEntry(0, 0, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(0);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
data.append(char(0));
|
||||
data.append(char(i * 32));
|
||||
data.append(char(0));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture, QRhiTextureUploadEntry(1, 0, QRhiTextureSubresourceUploadDescription(data)));
|
||||
if (mipmaps)
|
||||
d.initialUpdates->generateMips(texture);
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(1);
|
||||
readbackDescription.setLevel(0);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
//
|
||||
// 1D texture with uploaded mipmaps. Contains yellow colormap
|
||||
//
|
||||
texture = m_r->newTexture(
|
||||
QRhiTexture::Format::RGBA8, 8, 0, 0, 1,
|
||||
QRhiTexture::Flag::OneDimensional | QRhiTexture::Flag::UsedAsTransferSource
|
||||
| (mipmaps ? QRhiTexture::Flag::MipMapped : QRhiTexture::Flag(0)));
|
||||
d.releasePool << texture;
|
||||
texture->create();
|
||||
|
||||
shaderResouceBindings.append(QRhiShaderResourceBinding::sampledTexture(
|
||||
3, QRhiShaderResourceBinding::FragmentStage, texture,
|
||||
texture->flags().testFlag(QRhiTexture::Flag::MipMapped) ? samplerNearest
|
||||
: samplerNone));
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
data.append(char(i * 32));
|
||||
data.append(char(i * 32));
|
||||
data.append(char(0));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture, QRhiTextureUploadEntry(0, 0, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(0);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
QRhiTexture *textureSource = texture;
|
||||
QByteArray textureCopyData = data.mid(data.size() / 2).append(data.mid(0, data.size() / 2));
|
||||
|
||||
if (mipmaps) {
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
data.append(char(i * 64));
|
||||
data.append(char(i * 64));
|
||||
data.append(char(0));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture,
|
||||
QRhiTextureUploadEntry(0, 1, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(1);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
data.append(char(i * 128));
|
||||
data.append(char(i * 128));
|
||||
data.append(char(0));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture,
|
||||
QRhiTextureUploadEntry(0, 2, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(2);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
data.clear();
|
||||
data.append(char(128));
|
||||
data.append(char(128));
|
||||
data.append(char(0));
|
||||
data.append(char(255));
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture,
|
||||
QRhiTextureUploadEntry(0, 3, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(3);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
}
|
||||
|
||||
//
|
||||
// 1D texture array with uploaded mipmaps. Layer 0 contains blue colormap, layer 1 contains
|
||||
// magenta colormap
|
||||
//
|
||||
texture = m_r->newTextureArray(
|
||||
QRhiTexture::Format::RGBA8, 2, QSize(8, 0), 1,
|
||||
QRhiTexture::Flag::TextureArray | QRhiTexture::Flag::OneDimensional
|
||||
| QRhiTexture::Flag::UsedAsTransferSource
|
||||
| (mipmaps ? QRhiTexture::Flag::MipMapped : QRhiTexture::Flag(0)));
|
||||
d.releasePool << texture;
|
||||
texture->create();
|
||||
|
||||
shaderResouceBindings.append(QRhiShaderResourceBinding::sampledTexture(
|
||||
4, QRhiShaderResourceBinding::FragmentStage, texture,
|
||||
texture->flags().testFlag(QRhiTexture::Flag::MipMapped) ? samplerNearest
|
||||
: samplerNone));
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
data.append(char(0));
|
||||
data.append(char(0));
|
||||
data.append(char(i * 32));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture, QRhiTextureUploadEntry(0, 0, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(0);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
QRhiTexture *textureArraySource = texture;
|
||||
QList<QByteArray> textureArrayCopyData;
|
||||
textureArrayCopyData.append(data.mid(data.size() / 2).append(data.mid(0, data.size() / 2)));
|
||||
|
||||
if (mipmaps) {
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
data.append(char(0));
|
||||
data.append(char(0));
|
||||
data.append(char(i * 64));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture,
|
||||
QRhiTextureUploadEntry(0, 1, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(1);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
data.append(char(0));
|
||||
data.append(char(0));
|
||||
data.append(char(i * 128));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture,
|
||||
QRhiTextureUploadEntry(0, 2, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(2);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
data.clear();
|
||||
data.append(char(0));
|
||||
data.append(char(0));
|
||||
data.append(char(128));
|
||||
data.append(char(255));
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture,
|
||||
QRhiTextureUploadEntry(0, 3, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(3);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
}
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
data.append(char(i * 32));
|
||||
data.append(char(0));
|
||||
data.append(char(i * 32));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture, QRhiTextureUploadEntry(1, 0, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(1);
|
||||
readbackDescription.setLevel(0);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
textureArrayCopyData.append(data.mid(data.size() / 2).append(data.mid(0, data.size() / 2)));
|
||||
|
||||
if (mipmaps) {
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
data.append(char(i * 64));
|
||||
data.append(char(0));
|
||||
data.append(char(i * 64));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture,
|
||||
QRhiTextureUploadEntry(1, 1, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(1);
|
||||
readbackDescription.setLevel(1);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
data.clear();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
data.append(char(i * 128));
|
||||
data.append(char(0));
|
||||
data.append(char(i * 128));
|
||||
data.append(char(255));
|
||||
}
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture,
|
||||
QRhiTextureUploadEntry(1, 2, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(1);
|
||||
readbackDescription.setLevel(2);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
data.clear();
|
||||
data.append(char(128));
|
||||
data.append(char(0));
|
||||
data.append(char(128));
|
||||
data.append(char(255));
|
||||
d.initialUpdates->uploadTexture(
|
||||
texture,
|
||||
QRhiTextureUploadEntry(1, 3, QRhiTextureSubresourceUploadDescription(data)));
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, data);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(1);
|
||||
readbackDescription.setLevel(3);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
}
|
||||
|
||||
//
|
||||
// 1D Texture loaded from image - contains rainbow colormap
|
||||
//
|
||||
QImage image(256, 1, QImage::Format_RGBA8888);
|
||||
for (int i = 0; i < image.width(); ++i) {
|
||||
float x = float(i) / float(image.width() - 1);
|
||||
if (x < 2.0f / 5.0f) {
|
||||
image.setPixelColor(i, 0, QColor::fromRgbF(1.0f, 5.0f / 2.0f * x, 0.0f));
|
||||
} else if (x < 3.0f / 5.0f) {
|
||||
image.setPixelColor(i, 0, QColor::fromRgbF(-5.0f * x + 3.0f, 1.0f, 0.0f));
|
||||
} else if (x < 4.0f / 5.0f) {
|
||||
image.setPixelColor(i, 0, QColor::fromRgbF(0.0f, -5.0f * x + 4.0f, 5.0f * x - 3.0f));
|
||||
} else {
|
||||
image.setPixelColor(i, 0, QColor::fromRgbF(10.0f / 3.0f * x - 8.0f / 3.0f, 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
texture = m_r->newTexture(QRhiTexture::Format::RGBA8, image.width(), 0, 0, 1,
|
||||
QRhiTexture::Flag::OneDimensional);
|
||||
d.releasePool << texture;
|
||||
texture->create();
|
||||
|
||||
shaderResouceBindings.append(QRhiShaderResourceBinding::sampledTexture(
|
||||
5, QRhiShaderResourceBinding::FragmentStage, texture,
|
||||
texture->flags().testFlag(QRhiTexture::Flag::MipMapped) ? samplerNearest
|
||||
: samplerNone));
|
||||
|
||||
d.initialUpdates->uploadTexture(texture, image);
|
||||
|
||||
//
|
||||
// 1D Texture copied
|
||||
//
|
||||
texture = m_r->newTexture(QRhiTexture::Format::RGBA8, 8, 0, 0, 1,
|
||||
QRhiTexture::Flag::OneDimensional
|
||||
| QRhiTexture::Flag::UsedAsTransferSource);
|
||||
d.releasePool << texture;
|
||||
texture->create();
|
||||
|
||||
shaderResouceBindings.append(QRhiShaderResourceBinding::sampledTexture(
|
||||
6, QRhiShaderResourceBinding::FragmentStage, texture,
|
||||
texture->flags().testFlag(QRhiTexture::Flag::MipMapped) ? samplerNearest
|
||||
: samplerNone));
|
||||
|
||||
QRhiTextureCopyDescription copyDescription;
|
||||
copyDescription.setSourceLayer(0);
|
||||
copyDescription.setSourceLevel(0);
|
||||
copyDescription.setSourceTopLeft(QPoint(4, 0));
|
||||
copyDescription.setDestinationLayer(0);
|
||||
copyDescription.setDestinationLevel(0);
|
||||
copyDescription.setDestinationTopLeft(QPoint(0, 0));
|
||||
copyDescription.setPixelSize(QSize(4, 1));
|
||||
|
||||
d.initialUpdates->copyTexture(texture, textureSource, copyDescription);
|
||||
|
||||
copyDescription.setSourceTopLeft(QPoint(0, 0));
|
||||
copyDescription.setDestinationTopLeft(QPoint(4, 0));
|
||||
|
||||
d.initialUpdates->copyTexture(texture, textureSource, copyDescription);
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed = std::bind(readBackCompleted, readbackResult, textureCopyData);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(0);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
//
|
||||
// 1D Texture array copied
|
||||
//
|
||||
texture = m_r->newTextureArray(QRhiTexture::Format::RGBA8, 2, QSize(8, 0), 1,
|
||||
QRhiTexture::Flag::OneDimensional
|
||||
| QRhiTexture::Flag::UsedAsTransferSource);
|
||||
d.releasePool << texture;
|
||||
texture->create();
|
||||
|
||||
shaderResouceBindings.append(QRhiShaderResourceBinding::sampledTexture(
|
||||
7, QRhiShaderResourceBinding::FragmentStage, texture,
|
||||
texture->flags().testFlag(QRhiTexture::Flag::MipMapped) ? samplerNearest
|
||||
: samplerNone));
|
||||
|
||||
copyDescription.setSourceLayer(1);
|
||||
copyDescription.setSourceLevel(0);
|
||||
copyDescription.setSourceTopLeft(QPoint(4, 0));
|
||||
copyDescription.setDestinationLayer(0);
|
||||
copyDescription.setDestinationLevel(0);
|
||||
copyDescription.setDestinationTopLeft(QPoint(0, 0));
|
||||
copyDescription.setPixelSize(QSize(4, 1));
|
||||
d.initialUpdates->copyTexture(texture, textureArraySource, copyDescription);
|
||||
|
||||
copyDescription.setSourceTopLeft(QPoint(0, 0));
|
||||
copyDescription.setDestinationTopLeft(QPoint(4, 0));
|
||||
d.initialUpdates->copyTexture(texture, textureArraySource, copyDescription);
|
||||
|
||||
copyDescription.setSourceLayer(0);
|
||||
copyDescription.setDestinationLayer(1);
|
||||
d.initialUpdates->copyTexture(texture, textureArraySource, copyDescription);
|
||||
|
||||
copyDescription.setSourceTopLeft(QPoint(4, 0));
|
||||
copyDescription.setDestinationTopLeft(QPoint(0, 0));
|
||||
d.initialUpdates->copyTexture(texture, textureArraySource, copyDescription);
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed =
|
||||
std::bind(readBackCompleted, readbackResult, textureArrayCopyData[0]);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(1);
|
||||
readbackDescription.setLevel(0);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
readbackResult = new QRhiReadbackResult;
|
||||
readbackResult->completed =
|
||||
std::bind(readBackCompleted, readbackResult, textureArrayCopyData[1]);
|
||||
readbackDescription.setTexture(texture);
|
||||
readbackDescription.setLayer(0);
|
||||
readbackDescription.setLevel(0);
|
||||
d.initialUpdates->readBackTexture(readbackDescription, readbackResult);
|
||||
|
||||
//
|
||||
// Shader resource bindings
|
||||
//
|
||||
d.srb = m_r->newShaderResourceBindings();
|
||||
d.releasePool << d.srb;
|
||||
d.srb->setBindings(shaderResouceBindings.cbegin(), shaderResouceBindings.cend());
|
||||
d.srb->create();
|
||||
|
||||
//
|
||||
// Pipeline
|
||||
//
|
||||
d.ps = m_r->newGraphicsPipeline();
|
||||
d.releasePool << d.ps;
|
||||
d.ps->setShaderStages(
|
||||
{ { QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture1d.vert.qsb")) },
|
||||
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture1d.frag.qsb")) } });
|
||||
|
||||
QRhiVertexInputLayout inputLayout;
|
||||
inputLayout.setBindings({ { 4 * sizeof(float) } });
|
||||
inputLayout.setAttributes(
|
||||
{ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
|
||||
{ 0, 1, QRhiVertexInputAttribute::Float2, quint32(2 * sizeof(float)) } });
|
||||
|
||||
d.ps->setVertexInputLayout(inputLayout);
|
||||
d.ps->setShaderResourceBindings(d.srb);
|
||||
d.ps->setRenderPassDescriptor(m_rp);
|
||||
d.ps->create();
|
||||
}
|
||||
|
||||
void Window::customRelease()
|
||||
{
|
||||
qDeleteAll(d.releasePool);
|
||||
d.releasePool.clear();
|
||||
}
|
||||
|
||||
void Window::customRender()
|
||||
{
|
||||
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
|
||||
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
|
||||
|
||||
if (d.initialUpdates) {
|
||||
u->merge(d.initialUpdates);
|
||||
d.initialUpdates->release();
|
||||
d.initialUpdates = nullptr;
|
||||
}
|
||||
|
||||
u->updateDynamicBuffer(d.uniformBuffer, 0, 4, &d.index);
|
||||
d.index++;
|
||||
|
||||
cb->beginPass(m_sc->currentFrameRenderTarget(), m_clearColor, { 1.0f, 0 }, u);
|
||||
cb->setGraphicsPipeline(d.ps);
|
||||
cb->setShaderResources(d.srb);
|
||||
const QSize outputSizeInPixels = m_sc->currentPixelSize();
|
||||
cb->setViewport(
|
||||
{ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
|
||||
QRhiCommandBuffer::VertexInput vbufBinding(d.vertexBuffer, 0);
|
||||
cb->setVertexInput(0, 1, &vbufBinding, d.indexBuffer, 0, QRhiCommandBuffer::IndexUInt16);
|
||||
cb->drawIndexed(6);
|
||||
cb->endPass();
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#version 440
|
||||
|
||||
layout(location = 0) in vec2 v_texcoord;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(std140, binding = 0) uniform buf {
|
||||
int idx;
|
||||
} ubuf;
|
||||
|
||||
layout(binding = 1) uniform sampler1D tex;
|
||||
layout(binding = 2) uniform sampler1DArray texArray;
|
||||
layout(binding = 3) uniform sampler1D texA;
|
||||
layout(binding = 4) uniform sampler1DArray texArrayA;
|
||||
layout(binding = 5) uniform sampler1D texB;
|
||||
layout(binding = 6) uniform sampler1D texC;
|
||||
layout(binding = 7) uniform sampler1DArray texArrayB;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 c = vec4(v_texcoord, 0, 1);
|
||||
|
||||
vec2 coord = vec2(v_texcoord.x, floor(v_texcoord.y*2));
|
||||
|
||||
switch((ubuf.idx/(60*2))%7) {
|
||||
case 0:
|
||||
c = textureLod(tex, v_texcoord.x, float((ubuf.idx/30)%4));
|
||||
break;
|
||||
case 1:
|
||||
c = textureLod(texArray, coord, float((ubuf.idx/30)%4));
|
||||
break;
|
||||
case 2:
|
||||
c = textureLod(texA, v_texcoord.x, float((ubuf.idx/30)%4));
|
||||
break;
|
||||
case 3:
|
||||
c = textureLod(texArrayA, coord, float((ubuf.idx/30)%4));
|
||||
break;
|
||||
case 4:
|
||||
c = texture(texB, v_texcoord.x);
|
||||
break;
|
||||
case 5:
|
||||
c = texture(texC, v_texcoord.x);
|
||||
break;
|
||||
case 6:
|
||||
c = texture(texArrayB, coord);
|
||||
break;
|
||||
}
|
||||
|
||||
fragColor = vec4(c.rgb*c.a, c.a);
|
||||
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,14 @@
|
|||
#version 440
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
layout(location = 1) in vec2 texcoord;
|
||||
|
||||
layout(location = 0) out vec2 v_texcoord;
|
||||
|
||||
out gl_PerVertex { vec4 gl_Position; };
|
||||
|
||||
void main()
|
||||
{
|
||||
v_texcoord = texcoord;
|
||||
gl_Position = position;
|
||||
}
|
||||
Binary file not shown.
Loading…
Reference in New Issue