bool Image::preMultiply() { if(getSurfaceFormat() != CAIRO_FORMAT_ARGB32) return false; for(int p = 0; p < _s * _t; p++) { unsigned int offset = p * 4; unsigned char alpha = _data[offset + 3]; _data[offset] = (_data[offset] * alpha) / 255; _data[offset + 1] = (_data[offset + 1] * alpha) / 255; _data[offset + 2] = (_data[offset + 2] * alpha) / 255; } dirty(); return true; }
vk::Format getSurfaceFormat(latte::SQ_DATA_FORMAT format, latte::SQ_NUM_FORMAT numFormat, latte::SQ_FORMAT_COMP formatComp, uint32_t degamma, bool forDepthBuffer) { static const vk::Format BADFMT = vk::Format::eUndefined; auto pick = [=](vk::Format unorm, vk::Format snorm, vk::Format uint, vk::Format sint, vk::Format srgb, vk::Format scaled) { auto pickedFormat = getSurfaceFormat(numFormat, formatComp, degamma, unorm, snorm, uint, sint, srgb, scaled); if (pickedFormat == BADFMT) { decaf_abort(fmt::format("Failed to pick vulkan format for latte format: {} {} {} {}", format, numFormat, formatComp, degamma)); } return pickedFormat; }; bool isSigned = formatComp == latte::SQ_FORMAT_COMP::SIGNED; if (forDepthBuffer) { /* vk::Format::eD32Sfloat; vk::Format::eD32SfloatS8Uint vk::Format::eD16Unorm; vk::Format::eD16UnormS8Uint; vk::Format::eD24UnormS8Uint; */ switch (format) { case latte::SQ_DATA_FORMAT::FMT_32_FLOAT: return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, vk::Format::eD32Sfloat); case latte::SQ_DATA_FORMAT::FMT_8_24: return pick(vk::Format::eD24UnormS8Uint, BADFMT, BADFMT, BADFMT, BADFMT, BADFMT); default: decaf_abort("Unexpected depth buffer format for vulkan"); } } else { switch (format) { case latte::SQ_DATA_FORMAT::FMT_8: return pick(vk::Format::eR8Unorm, vk::Format::eR8Snorm, vk::Format::eR8Uint, vk::Format::eR8Sint, vk::Format::eR8Srgb, vk::Format::eR8Sscaled); //case latte::SQ_DATA_FORMAT::FMT_4_4: //case latte::SQ_DATA_FORMAT::FMT_3_3_2: case latte::SQ_DATA_FORMAT::FMT_16: return pick(vk::Format::eR16Unorm, vk::Format::eR16Snorm, vk::Format::eR16Uint, vk::Format::eR16Sint, BADFMT, vk::Format::eR16Sscaled); case latte::SQ_DATA_FORMAT::FMT_16_FLOAT: return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, vk::Format::eR16Sfloat); case latte::SQ_DATA_FORMAT::FMT_8_8: return pick(vk::Format::eR8G8Unorm, vk::Format::eR8G8Snorm, vk::Format::eR8G8Uint, vk::Format::eR8G8Sint, vk::Format::eR8G8Srgb, vk::Format::eR8G8Sscaled); case latte::SQ_DATA_FORMAT::FMT_5_6_5: return pick(vk::Format::eB5G6R5UnormPack16, BADFMT, BADFMT, BADFMT, BADFMT, BADFMT); //case latte::SQ_DATA_FORMAT::FMT_6_5_5: //case latte::SQ_DATA_FORMAT::FMT_1_5_5_5: //case latte::SQ_DATA_FORMAT::FMT_4_4_4_4: //case latte::SQ_DATA_FORMAT::FMT_5_5_5_1: case latte::SQ_DATA_FORMAT::FMT_32: return pick(BADFMT, BADFMT, vk::Format::eR32Uint, vk::Format::eR32Sint, BADFMT, BADFMT); case latte::SQ_DATA_FORMAT::FMT_32_FLOAT: return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, vk::Format::eR32Sfloat); case latte::SQ_DATA_FORMAT::FMT_16_16: return pick(vk::Format::eR16G16Unorm, vk::Format::eR16G16Snorm, vk::Format::eR16G16Uint, vk::Format::eR16G16Sint, BADFMT, BADFMT); case latte::SQ_DATA_FORMAT::FMT_16_16_FLOAT: return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, vk::Format::eR16G16Sfloat); //case latte::SQ_DATA_FORMAT::FMT_8_24: //case latte::SQ_DATA_FORMAT::FMT_8_24_FLOAT: case latte::SQ_DATA_FORMAT::FMT_24_8: return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, BADFMT); //case latte::SQ_DATA_FORMAT::FMT_24_8_FLOAT: //case latte::SQ_DATA_FORMAT::FMT_10_11_11: case latte::SQ_DATA_FORMAT::FMT_10_11_11_FLOAT: decaf_abort("Encountered bit-reversed surface format"); //return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, vk::Format::eB10G11R11UfloatPack32); //case latte::SQ_DATA_FORMAT::FMT_11_11_10: case latte::SQ_DATA_FORMAT::FMT_11_11_10_FLOAT: decaf_abort("Encountered bit-reversed surface format"); //return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, vk::Format::eB10G11R11UfloatPack32); case latte::SQ_DATA_FORMAT::FMT_2_10_10_10: decaf_abort("Encountered bit-reversed surface format"); //return pick(vk::Format::eA2B10G10R10UnormPack32, vk::Format::eA2B10G10R10SnormPack32, vk::Format::eA2B10G10R10UintPack32, vk::Format::eA2B10G10R10UnormPack32, BADFMT, BADFMT); case latte::SQ_DATA_FORMAT::FMT_8_8_8_8: return pick(vk::Format::eR8G8B8A8Unorm, vk::Format::eR8G8B8A8Snorm, vk::Format::eR8G8B8A8Uint, vk::Format::eR8G8B8A8Sint, vk::Format::eR8G8B8A8Srgb, vk::Format::eR8G8B8A8Sscaled); case latte::SQ_DATA_FORMAT::FMT_10_10_10_2: return pick(vk::Format::eA2B10G10R10UnormPack32, vk::Format::eA2B10G10R10SnormPack32, vk::Format::eA2B10G10R10UintPack32, vk::Format::eA2B10G10R10SintPack32, BADFMT, vk::Format::eA2B10G10R10SscaledPack32); //case latte::SQ_DATA_FORMAT::FMT_X24_8_32_FLOAT: case latte::SQ_DATA_FORMAT::FMT_32_32: return pick(BADFMT, BADFMT, vk::Format::eR32G32Uint, vk::Format::eR32G32Sint, BADFMT, BADFMT); case latte::SQ_DATA_FORMAT::FMT_32_32_FLOAT: return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, vk::Format::eR32G32Sfloat); case latte::SQ_DATA_FORMAT::FMT_16_16_16_16: return pick(vk::Format::eR16G16B16A16Unorm, vk::Format::eR16G16B16A16Snorm, vk::Format::eR16G16B16A16Uint, vk::Format::eR16G16B16A16Sint, BADFMT, BADFMT); case latte::SQ_DATA_FORMAT::FMT_16_16_16_16_FLOAT: return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, vk::Format::eR16G16B16A16Sfloat); case latte::SQ_DATA_FORMAT::FMT_32_32_32_32: return pick(BADFMT, BADFMT, vk::Format::eR32G32B32Uint, vk::Format::eR32G32B32Sint, BADFMT, BADFMT); case latte::SQ_DATA_FORMAT::FMT_32_32_32_32_FLOAT: return pick(BADFMT, BADFMT, BADFMT, BADFMT, BADFMT, vk::Format::eR32G32B32Sfloat); //case latte::SQ_DATA_FORMAT::FMT_1: //case latte::SQ_DATA_FORMAT::FMT_GB_GR: //case latte::SQ_DATA_FORMAT::FMT_BG_RG: //case latte::SQ_DATA_FORMAT::FMT_32_AS_8: //case latte::SQ_DATA_FORMAT::FMT_32_AS_8_8: //case latte::SQ_DATA_FORMAT::FMT_5_9_9_9_SHAREDEXP: //case latte::SQ_DATA_FORMAT::FMT_8_8_8: //case latte::SQ_DATA_FORMAT::FMT_16_16_16: //case latte::SQ_DATA_FORMAT::FMT_16_16_16_FLOAT: //case latte::SQ_DATA_FORMAT::FMT_32_32_32: //case latte::SQ_DATA_FORMAT::FMT_32_32_32_FLOAT: case latte::SQ_DATA_FORMAT::FMT_BC1: return pick(vk::Format::eBc1RgbaUnormBlock, BADFMT, BADFMT, BADFMT, vk::Format::eBc1RgbaSrgbBlock, BADFMT); case latte::SQ_DATA_FORMAT::FMT_BC2: return pick(vk::Format::eBc2UnormBlock, BADFMT, BADFMT, BADFMT, vk::Format::eBc2SrgbBlock, BADFMT); case latte::SQ_DATA_FORMAT::FMT_BC3: return pick(vk::Format::eBc3UnormBlock, BADFMT, BADFMT, BADFMT, vk::Format::eBc3SrgbBlock, BADFMT); case latte::SQ_DATA_FORMAT::FMT_BC4: return pick(vk::Format::eBc4UnormBlock, vk::Format::eBc4SnormBlock, BADFMT, BADFMT, BADFMT, BADFMT); case latte::SQ_DATA_FORMAT::FMT_BC5: return pick(vk::Format::eBc5UnormBlock, vk::Format::eBc5SnormBlock, BADFMT, BADFMT, BADFMT, BADFMT); //case latte::SQ_DATA_FORMAT::FMT_APC0: //case latte::SQ_DATA_FORMAT::FMT_APC1: //case latte::SQ_DATA_FORMAT::FMT_APC2: //case latte::SQ_DATA_FORMAT::FMT_APC3: //case latte::SQ_DATA_FORMAT::FMT_APC4: //case latte::SQ_DATA_FORMAT::FMT_APC5: //case latte::SQ_DATA_FORMAT::FMT_APC6: //case latte::SQ_DATA_FORMAT::FMT_APC7: //case latte::SQ_DATA_FORMAT::FMT_CTX1: default: decaf_abort("Unexpected color buffer format for vulkan"); } } }
void Driver::checkCurrentRenderPass() { HashedDesc<RenderPassDesc> currentDesc = getRenderPassDesc(); if (mCurrentRenderPass && mCurrentRenderPass->desc == currentDesc) { // Already active, nothing to do. return; } auto& foundRp = mRenderPasses[currentDesc.hash()]; if (foundRp) { mCurrentRenderPass = foundRp; return; } foundRp = new RenderPassObject(); foundRp->desc = currentDesc; std::vector<vk::AttachmentDescription> attachmentDescs; std::array<vk::AttachmentReference, latte::MaxRenderTargets> colorAttachmentRefs; vk::AttachmentReference depthAttachmentRef; for (auto i = 0u; i < latte::MaxRenderTargets; ++i) { auto &colorTarget = currentDesc->colorTargets[i]; if (!colorTarget.isEnabled) { colorAttachmentRefs[i].attachment = VK_ATTACHMENT_UNUSED; colorAttachmentRefs[i].layout = vk::ImageLayout::eColorAttachmentOptimal; foundRp->colorAttachmentIndexes[i] = -1; continue; } auto dataFormat = latte::getColorBufferDataFormat(colorTarget.format, colorTarget.numberType); auto vulkanFormat = getSurfaceFormat(dataFormat.format, dataFormat.numFormat, dataFormat.formatComp, dataFormat.degamma, false); vk::AttachmentDescription colorAttachmentDesc; colorAttachmentDesc.format = vulkanFormat; colorAttachmentDesc.samples = vk::SampleCountFlagBits::e1; colorAttachmentDesc.loadOp = vk::AttachmentLoadOp::eLoad; colorAttachmentDesc.storeOp = vk::AttachmentStoreOp::eStore; colorAttachmentDesc.stencilLoadOp = vk::AttachmentLoadOp::eDontCare; colorAttachmentDesc.stencilStoreOp = vk::AttachmentStoreOp::eDontCare; colorAttachmentDesc.initialLayout = vk::ImageLayout::eColorAttachmentOptimal; colorAttachmentDesc.finalLayout = vk::ImageLayout::eColorAttachmentOptimal; attachmentDescs.push_back(colorAttachmentDesc); auto attachmentIndex = static_cast<uint32_t>(attachmentDescs.size() - 1); colorAttachmentRefs[i].attachment = attachmentIndex; colorAttachmentRefs[i].layout = vk::ImageLayout::eColorAttachmentOptimal; foundRp->colorAttachmentIndexes[i] = attachmentIndex; } if (!currentDesc->depthTarget.isEnabled) { depthAttachmentRef.attachment = VK_ATTACHMENT_UNUSED; depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; foundRp->depthAttachmentIndex = -1; } else { auto depthTarget = currentDesc->depthTarget; auto dataFormat = latte::getDepthBufferDataFormat(depthTarget.format); auto vulkanFormat = getSurfaceFormat(dataFormat.format, dataFormat.numFormat, dataFormat.formatComp, dataFormat.degamma, true); vk::AttachmentDescription depthAttachmentDesc; depthAttachmentDesc.format = vulkanFormat; depthAttachmentDesc.samples = vk::SampleCountFlagBits::e1; depthAttachmentDesc.loadOp = vk::AttachmentLoadOp::eLoad; depthAttachmentDesc.storeOp = vk::AttachmentStoreOp::eStore; depthAttachmentDesc.stencilLoadOp = vk::AttachmentLoadOp::eLoad; depthAttachmentDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; depthAttachmentDesc.initialLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; depthAttachmentDesc.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; attachmentDescs.push_back(depthAttachmentDesc); auto attachmentIndex = static_cast<uint32_t>(attachmentDescs.size() - 1); depthAttachmentRef.attachment = attachmentIndex; depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal; foundRp->depthAttachmentIndex = attachmentIndex; } vk::SubpassDescription genericSubpass; genericSubpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics; genericSubpass.inputAttachmentCount = 0; genericSubpass.pInputAttachments = nullptr; genericSubpass.colorAttachmentCount = static_cast<uint32_t>(colorAttachmentRefs.size()); genericSubpass.pColorAttachments = colorAttachmentRefs.data(); genericSubpass.pResolveAttachments = 0; genericSubpass.pDepthStencilAttachment = &depthAttachmentRef; genericSubpass.preserveAttachmentCount = 0; genericSubpass.pPreserveAttachments = nullptr; vk::RenderPassCreateInfo renderPassDesc; renderPassDesc.attachmentCount = static_cast<uint32_t>(attachmentDescs.size()); renderPassDesc.pAttachments = attachmentDescs.data(); renderPassDesc.subpassCount = 1; renderPassDesc.pSubpasses = &genericSubpass; renderPassDesc.dependencyCount = 0; renderPassDesc.pDependencies = nullptr; auto renderPass = mDevice.createRenderPass(renderPassDesc); foundRp->renderPass = renderPass; mCurrentRenderPass = foundRp; }
bool GLDriver::checkActiveTextures() { std::vector<uint8_t> untiledImage, untiledMipmap; gx2::GX2Surface surface; for (auto i = 0; i < latte::MaxTextures; ++i) { auto resourceOffset = (latte::SQ_PS_TEX_RESOURCE_0 + i) * 7; auto sq_tex_resource_word0 = getRegister<latte::SQ_TEX_RESOURCE_WORD0_N>(latte::Register::SQ_TEX_RESOURCE_WORD0_0 + 4 * resourceOffset); auto sq_tex_resource_word1 = getRegister<latte::SQ_TEX_RESOURCE_WORD1_N>(latte::Register::SQ_TEX_RESOURCE_WORD1_0 + 4 * resourceOffset); auto sq_tex_resource_word2 = getRegister<latte::SQ_TEX_RESOURCE_WORD2_N>(latte::Register::SQ_TEX_RESOURCE_WORD2_0 + 4 * resourceOffset); auto sq_tex_resource_word3 = getRegister<latte::SQ_TEX_RESOURCE_WORD3_N>(latte::Register::SQ_TEX_RESOURCE_WORD3_0 + 4 * resourceOffset); auto sq_tex_resource_word4 = getRegister<latte::SQ_TEX_RESOURCE_WORD4_N>(latte::Register::SQ_TEX_RESOURCE_WORD4_0 + 4 * resourceOffset); auto sq_tex_resource_word5 = getRegister<latte::SQ_TEX_RESOURCE_WORD5_N>(latte::Register::SQ_TEX_RESOURCE_WORD5_0 + 4 * resourceOffset); auto sq_tex_resource_word6 = getRegister<latte::SQ_TEX_RESOURCE_WORD6_N>(latte::Register::SQ_TEX_RESOURCE_WORD6_0 + 4 * resourceOffset); auto baseAddress = sq_tex_resource_word2.BASE_ADDRESS() << 8; if (!baseAddress) { continue; } if (baseAddress == mPixelTextureCache[i].baseAddress && sq_tex_resource_word0.value == mPixelTextureCache[i].word0 && sq_tex_resource_word1.value == mPixelTextureCache[i].word1 && sq_tex_resource_word2.value == mPixelTextureCache[i].word2 && sq_tex_resource_word3.value == mPixelTextureCache[i].word3 && sq_tex_resource_word4.value == mPixelTextureCache[i].word4 && sq_tex_resource_word5.value == mPixelTextureCache[i].word5 && sq_tex_resource_word6.value == mPixelTextureCache[i].word6) { continue; // No change in sampler state } mPixelTextureCache[i].baseAddress = baseAddress; mPixelTextureCache[i].word0 = sq_tex_resource_word0.value; mPixelTextureCache[i].word1 = sq_tex_resource_word1.value; mPixelTextureCache[i].word2 = sq_tex_resource_word2.value; mPixelTextureCache[i].word3 = sq_tex_resource_word3.value; mPixelTextureCache[i].word4 = sq_tex_resource_word4.value; mPixelTextureCache[i].word5 = sq_tex_resource_word5.value; mPixelTextureCache[i].word6 = sq_tex_resource_word6.value; // Decode resource registers auto pitch = (sq_tex_resource_word0.PITCH() + 1) * 8; auto width = sq_tex_resource_word0.TEX_WIDTH() + 1; auto height = sq_tex_resource_word1.TEX_HEIGHT() + 1; auto depth = sq_tex_resource_word1.TEX_DEPTH() + 1; auto format = sq_tex_resource_word1.DATA_FORMAT(); auto tileMode = sq_tex_resource_word0.TILE_MODE(); auto numFormat = sq_tex_resource_word4.NUM_FORMAT_ALL(); auto formatComp = sq_tex_resource_word4.FORMAT_COMP_X(); auto degamma = sq_tex_resource_word4.FORCE_DEGAMMA(); auto dim = sq_tex_resource_word0.DIM(); auto buffer = getSurfaceBuffer(baseAddress, width, height, depth, dim, format, numFormat, formatComp, degamma, sq_tex_resource_word0.TILE_TYPE()); if (buffer->dirtyAsTexture) { auto swizzle = sq_tex_resource_word2.SWIZZLE() << 8; // Rebuild a GX2Surface std::memset(&surface, 0, sizeof(gx2::GX2Surface)); surface.dim = static_cast<gx2::GX2SurfaceDim>(dim); surface.width = width; surface.height = height; if (surface.dim == gx2::GX2SurfaceDim::TextureCube) { surface.depth = depth * 6; } else if (surface.dim == gx2::GX2SurfaceDim::Texture3D || surface.dim == gx2::GX2SurfaceDim::Texture2DMSAAArray || surface.dim == gx2::GX2SurfaceDim::Texture2DArray || surface.dim == gx2::GX2SurfaceDim::Texture1DArray) { surface.depth = depth; } else { surface.depth = 1; } surface.mipLevels = 1; surface.format = getSurfaceFormat(format, numFormat, formatComp, degamma); surface.aa = gx2::GX2AAMode::Mode1X; surface.use = gx2::GX2SurfaceUse::Texture; if (sq_tex_resource_word0.TILE_TYPE()) { surface.use |= gx2::GX2SurfaceUse::DepthBuffer; } surface.tileMode = static_cast<gx2::GX2TileMode>(tileMode); surface.swizzle = swizzle; // Update the sizing information for the surface GX2CalcSurfaceSizeAndAlignment(&surface); // Align address baseAddress &= ~(surface.alignment - 1); surface.image = make_virtual_ptr<uint8_t>(baseAddress); surface.mipmaps = nullptr; // Calculate a new memory CRC uint64_t newHash[2] = { 0 }; MurmurHash3_x64_128(surface.image, surface.imageSize, 0, newHash); // If the CPU memory has changed, we should re-upload this. This hashing is // also means that if the application temporarily uses one of its buffers as // a color buffer, we are able to accurately handle this. Providing they are // not updating the memory at the same time. if (newHash[0] != buffer->cpuMemHash[0] || newHash[1] != buffer->cpuMemHash[1]) { buffer->cpuMemHash[0] = newHash[0]; buffer->cpuMemHash[1] = newHash[1]; // Untile gx2::internal::convertTiling(&surface, untiledImage, untiledMipmap); // Create texture auto compressed = isCompressedFormat(format); auto target = getTextureTarget(dim); auto textureDataType = gl::GL_INVALID_ENUM; auto textureFormat = getTextureFormat(format); auto size = untiledImage.size(); if (compressed) { textureDataType = getCompressedTextureDataType(format, degamma); } else { textureDataType = getTextureDataType(format, formatComp); } if (textureDataType == gl::GL_INVALID_ENUM || textureFormat == gl::GL_INVALID_ENUM) { decaf_abort(fmt::format("Texture with unsupported format {}", surface.format.value())); } switch (dim) { case latte::SQ_TEX_DIM_1D: if (compressed) { gl::glCompressedTextureSubImage1D(buffer->object, 0, /* level */ 0, /* xoffset */ width, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage1D(buffer->object, 0, /* level */ 0, /* xoffset */ width, textureFormat, textureDataType, untiledImage.data()); } break; case latte::SQ_TEX_DIM_2D: if (compressed) { gl::glCompressedTextureSubImage2D(buffer->object, 0, /* level */ 0, 0, /* xoffset, yoffset */ width, height, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage2D(buffer->object, 0, /* level */ 0, 0, /* xoffset, yoffset */ width, height, textureFormat, textureDataType, untiledImage.data()); } break; case latte::SQ_TEX_DIM_3D: if (compressed) { gl::glCompressedTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, depth, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, depth, textureFormat, textureDataType, untiledImage.data()); } break; case latte::SQ_TEX_DIM_CUBEMAP: decaf_check(surface.depth == 6); case latte::SQ_TEX_DIM_2D_ARRAY: if (compressed) { gl::glCompressedTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, surface.depth, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, surface.depth, textureFormat, textureDataType, untiledImage.data()); } break; default: decaf_abort(fmt::format("Unsupported texture dim: {}", sq_tex_resource_word0.DIM())); } } buffer->dirtyAsTexture = false; buffer->state = SurfaceUseState::CpuWritten; } // Setup texture swizzle auto dst_sel_x = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_X()); auto dst_sel_y = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_Y()); auto dst_sel_z = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_Z()); auto dst_sel_w = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_W()); gl::GLint textureSwizzle[] = { static_cast<gl::GLint>(dst_sel_x), static_cast<gl::GLint>(dst_sel_y), static_cast<gl::GLint>(dst_sel_z), static_cast<gl::GLint>(dst_sel_w), }; gl::glTextureParameteriv(buffer->object, gl::GL_TEXTURE_SWIZZLE_RGBA, textureSwizzle); gl::glBindTextureUnit(i, buffer->object); } return true; }