29Manager::Manager(QSGDefaultRenderContext *rc,
const QSize &surfacePixelSize, QSurface *maybeSurface)
33 const int maxSize = m_rhi->resourceLimit(QRhi::TextureSizeMax);
37 const int widthHint = qMax(1, surfacePixelSize.width());
38 const int heightHint = qMax(1, surfacePixelSize.height());
39 int w = qMin(maxSize, qt_sg_envInt(
"QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(widthHint - 1))));
40 int h = qMin(maxSize, qt_sg_envInt(
"QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(heightHint - 1))));
42 if (maybeSurface && maybeSurface->surfaceClass() == QSurface::Window) {
43 QWindow *window =
static_cast<QWindow *>(maybeSurface);
45 if ((window->type() & Qt::CoverWindow) == Qt::CoverWindow) {
51 m_atlas_size_limit = qt_sg_envInt(
"QSG_ATLAS_SIZE_LIMIT", qMax(w, h) / 2);
52 m_atlas_size = QSize(w, h);
54 qCDebug(QSG_LOG_INFO,
"rhi texture atlas dimensions: %dx%d", w, h);
95 QSGTexture *t =
nullptr;
96 if (!qsgEnableCompressedAtlas() || !factory->textureData()->isValid())
99 unsigned int format = factory->textureData()->glInternalFormat();
100 QSGCompressedTexture::FormatInfo fmt = QSGCompressedTexture::formatInfo(format);
101 if (!m_rhi->isTextureFormatSupported(fmt.rhiFormat))
104 QSize size = factory->textureData()->size();
105 if (size.width() < m_atlas_size_limit && size.height() < m_atlas_size_limit) {
106 QHash<
unsigned int, QSGCompressedAtlasTexture::Atlas*>::iterator i = m_atlases.find(format);
107 if (i == m_atlases.cend()) {
108 auto newAtlas =
new QSGCompressedAtlasTexture::Atlas(m_rc, m_atlas_size, format);
109 i = m_atlases.insert(format, newAtlas);
111 const QTextureFileData *cmpData = factory->textureData();
112 t = i.value()->create(cmpData->getDataView(), size);
219 const QRect &r = tex->atlasSubRect();
220 QImage image = tex->image();
225 if (m_format == QRhiTexture::BGRA8) {
226 if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_ARGB32_Premultiplied)
227 image = std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
228 }
else if (image.format() != QImage::Format_RGBA8888_Premultiplied) {
229 image = std::move(image).convertToFormat(QImage::Format_RGBA8888_Premultiplied);
232 if (m_debug_overlay) {
234 p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
235 p.fillRect(0, 0, image.width(), image.height(), QBrush(QColor::fromRgbF(0, 1, 1, 0.5)));
238 const int iw = image.width();
239 const int ih = image.height();
240 const int bpl = image.bytesPerLine() / 4;
241 QVarLengthArray<quint32, 1024> tmpBits(qMax(iw + 2, ih + 2));
242 const int tmpBitsSize = tmpBits.size() * 4;
243 const quint32 *src =
reinterpret_cast<
const quint32 *>(image.constBits());
244 quint32 *dst = tmpBits.data();
245 QVarLengthArray<QRhiTextureUploadEntry, 5> entries;
249 memcpy(dst + 1, src, iw *
sizeof(quint32));
250 dst[1 + iw] = src[iw - 1];
253 subresDesc.setDestinationTopLeft(QPoint(r.x(), r.y()));
254 subresDesc.setSourceSize(QSize(iw + 2, 1));
255 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
259 const quint32 *lastRow = src + bpl * (ih - 1);
261 memcpy(dst + 1, lastRow, iw *
sizeof(quint32));
262 dst[1 + iw] = lastRow[iw - 1];
265 subresDesc.setDestinationTopLeft(QPoint(r.x(), r.y() + ih + 1));
266 subresDesc.setSourceSize(QSize(iw + 2, 1));
267 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
271 for (
int i = 0; i < ih; ++i)
272 dst[i] = src[i * bpl];
275 subresDesc.setDestinationTopLeft(QPoint(r.x(), r.y() + 1));
276 subresDesc.setSourceSize(QSize(1, ih));
277 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
282 for (
int i = 0; i < ih; ++i)
283 dst[i] = src[i * bpl + iw - 1];
286 subresDesc.setDestinationTopLeft(QPoint(r.x() + iw + 1, r.y() + 1));
287 subresDesc.setSourceSize(QSize(1, ih));
288 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
294 int ey = sy + r.height() - 2;
295 entries.reserve(4 + (ey - sy));
296 for (
int y = sy; y < ey; ++y) {
298 subresDesc.setDestinationTopLeft(QPoint(r.x() + 1, y));
299 subresDesc.setSourceSize(QSize(r.width() - 2, 1));
300 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
305 subresDesc.setDestinationTopLeft(QPoint(r.x() + 1, r.y() + 1));
306 subresDesc.setSourceSize(QSize(r.width() - 2, r.height() - 2));
307 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
311 desc.setEntries(entries.cbegin(), entries.cend());
312 resourceUpdates->uploadTexture(m_texture, desc);
314 const QSize textureSize = t->textureSize();
315 if (textureSize.width() > m_atlas_transient_image_threshold || textureSize.height() > m_atlas_transient_image_threshold)
318 qCDebug(QSG_LOG_TIME_TEXTURE,
"atlastexture upload enqueued in: %lldms (%dx%d)",
319 qsg_renderer_timer.elapsed(),
320 t->textureSize().width(),
321 t->textureSize().height());
385 if (!m_nonatlas_texture) {
386 m_nonatlas_texture =
new QSGPlainTexture;
387 if (!m_image.isNull()) {
388 m_nonatlas_texture->setImage(m_image);
389 m_nonatlas_texture->setFiltering(filtering());
393 Q_ASSERT(rhi->isRecordingFrame());
394 const QRect r = atlasSubRectWithoutPadding();
397 if (extractTex->create()) {
398 bool ownResUpd =
false;
399 QRhiResourceUpdateBatch *resUpd = resourceUpdates;
402 resUpd = rhi->nextResourceUpdateBatch();
405 desc.setSourceTopLeft(r.topLeft());
406 desc.setPixelSize(r.size());
407 resUpd->copyTexture(extractTex, m_atlas->texture(), desc);
409 rc->currentFrameCommandBuffer()->resourceUpdate(resUpd);
412 m_nonatlas_texture->setTexture(extractTex);
413 m_nonatlas_texture->setOwnsTexture(
true);
414 m_nonatlas_texture->setHasAlphaChannel(m_has_alpha);
415 m_nonatlas_texture->setTextureSize(r.size());
419 m_nonatlas_texture->setMipmapFiltering(mipmapFiltering());
420 m_nonatlas_texture->setFiltering(filtering());
421 return m_nonatlas_texture;
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
void enqueueTextureUpload(TextureBase *t, QRhiResourceUpdateBatch *resourceUpdates) override
QSGTexture * create(const QImage &image, bool hasAlphaChannel)
qint64 comparisonKey() const override
Returns a key suitable for comparing textures.
void commitTextureOperations(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates) override
Call this function to enqueue image upload operations to resourceUpdates, in case there are any pendi...
bool hasAlphaChannel() const override
Returns true if the texture data contains an alpha channel.
QSGTexture * removedFromAtlas(QRhiResourceUpdateBatch *resourceUpdates) const override
This function returns a copy of the current texture which is removed from its atlas.