text:
// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SpirvShader.hpp"

#include "System/Types.hpp"

#include "Vulkan/VkDescriptorSetLayout.hpp"
#include "Vulkan/VkPipelineLayout.hpp"

#include <spirv/unified1/spirv.hpp>

namespace {

VkFormat SpirvFormatToVulkanFormat(spv::ImageFormat format)
{
	switch(format)
	{
	case spv::ImageFormatRgba32f: return VK_FORMAT_R32G32B32A32_SFLOAT;
	case spv::ImageFormatRgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT;
	case spv::ImageFormatR32f: return VK_FORMAT_R32_SFLOAT;
	case spv::ImageFormatRgba8: return VK_FORMAT_R8G8B8A8_UNORM;
	case spv::ImageFormatRgba8Snorm: return VK_FORMAT_R8G8B8A8_SNORM;
	case spv::ImageFormatRg32f: return VK_FORMAT_R32G32_SFLOAT;
	case spv::ImageFormatRg16f: return VK_FORMAT_R16G16_SFLOAT;
	case spv::ImageFormatR11fG11fB10f: return VK_FORMAT_B10G11R11_UFLOAT_PACK32;
	case spv::ImageFormatR16f: return VK_FORMAT_R16_SFLOAT;
	case spv::ImageFormatRgba16: return VK_FORMAT_R16G16B16A16_UNORM;
	case spv::ImageFormatRgb10A2: return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
	case spv::ImageFormatRg16: return VK_FORMAT_R16G16_UNORM;
	case spv::ImageFormatRg8: return VK_FORMAT_R8G8_UNORM;
	case spv::ImageFormatR16: return VK_FORMAT_R16_UNORM;
	case spv::ImageFormatR8: return VK_FORMAT_R8_UNORM;
	case spv::ImageFormatRgba16Snorm: return VK_FORMAT_R16G16B16A16_SNORM;
	case spv::ImageFormatRg16Snorm: return VK_FORMAT_R16G16_SNORM;
	case spv::ImageFormatRg8Snorm: return VK_FORMAT_R8G8_SNORM;
	case spv::ImageFormatR16Snorm: return VK_FORMAT_R16_SNORM;
	case spv::ImageFormatR8Snorm: return VK_FORMAT_R8_SNORM;
	case spv::ImageFormatRgba32i: return VK_FORMAT_R32G32B32A32_SINT;
	case spv::ImageFormatRgba16i: return VK_FORMAT_R16G16B16A16_SINT;
	case spv::ImageFormatRgba8i: return VK_FORMAT_R8G8B8A8_SINT;
	case spv::ImageFormatR32i: return VK_FORMAT_R32_SINT;
	case spv::ImageFormatRg32i: return VK_FORMAT_R32G32_SINT;
	case spv::ImageFormatRg16i: return VK_FORMAT_R16G16_SINT;
	case spv::ImageFormatRg8i: return VK_FORMAT_R8G8_SINT;
	case spv::ImageFormatR16i: return VK_FORMAT_R16_SINT;
	case spv::ImageFormatR8i: return VK_FORMAT_R8_SINT;
	case spv::ImageFormatRgba32ui: return VK_FORMAT_R32G32B32A32_UINT;
	case spv::ImageFormatRgba16ui: return VK_FORMAT_R16G16B16A16_UINT;
	case spv::ImageFormatRgba8ui: return VK_FORMAT_R8G8B8A8_UINT;
	case spv::ImageFormatR32ui: return VK_FORMAT_R32_UINT;
	case spv::ImageFormatRgb10a2ui: return VK_FORMAT_A2B10G10R10_UINT_PACK32;
	case spv::ImageFormatRg32ui: return VK_FORMAT_R32G32_UINT;
	case spv::ImageFormatRg16ui: return VK_FORMAT_R16G16_UINT;
	case spv::ImageFormatRg8ui: return VK_FORMAT_R8G8_UINT;
	case spv::ImageFormatR16ui: return VK_FORMAT_R16_UINT;
	case spv::ImageFormatR8ui: return VK_FORMAT_R8_UINT;

	default:
		UNSUPPORTED("SPIR-V ImageFormat %u", format);
		return VK_FORMAT_UNDEFINED;
	}
}

sw::SIMD::Float sRGBtoLinear(sw::SIMD::Float c)
{
	sw::SIMD::Float lc = c * sw::SIMD::Float(1.0f / 12.92f);
	sw::SIMD::Float ec = sw::power((c + sw::SIMD::Float(0.055f)) * sw::SIMD::Float(1.0f / 1.055f), sw::SIMD::Float(2.4f));

	sw::SIMD::Int linear = CmpLT(c, sw::SIMD::Float(0.04045f));

	return rr::As<sw::SIMD::Float>((linear & rr::As<sw::SIMD::Int>(lc)) | (~linear & rr::As<sw::SIMD::Int>(ec)));  // TODO: IfThenElse()
}

}  // anonymous namespace

namespace sw {

SpirvShader::EmitResult SpirvShader::EmitImageSampleImplicitLod(Variant variant, InsnIterator insn, EmitState *state) const
{
	return EmitImageSample({ variant, Implicit }, insn, state);
}

SpirvShader::EmitResult SpirvShader::EmitImageGather(Variant variant, InsnIterator insn, EmitState *state) const
{
	ImageInstruction instruction = { variant, Gather };
	instruction.gatherComponent = !instruction.isDref() ? getObject(insn.word(5)).constantValue[0] : 0;

	return EmitImageSample(instruction, insn, state);
}

SpirvShader::EmitResult SpirvShader::EmitImageSampleExplicitLod(Variant variant, InsnIterator insn, EmitState *state) const
{
	auto isDref = (variant == Dref) || (variant == ProjDref);
	uint32_t imageOperands = static_cast<spv::ImageOperandsMask>(insn.word(isDref ? 6 : 5));
	imageOperands &= ~spv::ImageOperandsConstOffsetMask;  // Dealt with later.

	if((imageOperands & spv::ImageOperandsLodMask) == imageOperands)
	{
		return EmitImageSample({ variant, Lod }, insn, state);
	}
	else if((imageOperands & spv::ImageOperandsGradMask) == imageOperands)
	{
		return EmitImageSample({ variant, Grad }, insn, state);
	}
	else
		UNSUPPORTED("Image operands 0x%08X", imageOperands);

	return EmitResult::Continue;
}

SpirvShader::EmitResult SpirvShader::EmitImageFetch(InsnIterator insn, EmitState *state) const
{
	return EmitImageSample({ None, Fetch }, insn, state);
}

SpirvShader::EmitResult SpirvShader::EmitImageSample(ImageInstruction instruction, InsnIterator insn, EmitState *state) const
{
	auto &resultType = getType(insn.resultTypeId());
	auto &result = state->createIntermediate(insn.resultId(), resultType.componentCount);
	Array<SIMD::Float> out(4);

	// TODO(b/153380916): When we're in a code path that is always executed,
	// i.e. post-dominators of the entry block, we don't have to dynamically
	// check whether any lanes are active, and can elide the jump.
	If(AnyTrue(state->activeLaneMask()))
	{
		EmitImageSampleUnconditional(out, instruction, insn, state);
	}

	for(auto i = 0u; i < resultType.componentCount; i++) { result.move(i, out[i]); }

	return EmitResult::Continue;
}

void SpirvShader::EmitImageSampleUnconditional(Array<SIMD::Float> &out, ImageInstruction instruction, InsnIterator insn, EmitState *state) const
{
	Object::ID sampledImageId = insn.word(3);  // For OpImageFetch this is just an Image, not a SampledImage.
	Object::ID coordinateId = insn.word(4);

	auto imageDescriptor = state->getPointer(sampledImageId).base;  // vk::SampledImageDescriptor*

	// If using a separate sampler, look through the OpSampledImage instruction to find the sampler descriptor
	auto &sampledImage = getObject(sampledImageId);
	auto samplerDescriptor = (sampledImage.opcode() == spv::OpSampledImage) ? state->getPointer(sampledImage.definition.word(4)).base : imageDescriptor;

	auto coordinate = Operand(this, state, coordinateId);

	rr::Int samplerId = *Pointer<rr::Int>(samplerDescriptor + OFFSET(vk::SampledImageDescriptor, samplerId));  // vk::Sampler::id
	Pointer<Byte> texture = imageDescriptor + OFFSET(vk::SampledImageDescriptor, texture);                     // sw::Texture*

	// Above we assumed that if the SampledImage operand is not the result of an OpSampledImage,
	// it must be a combined image sampler loaded straight from the descriptor set. For OpImageFetch
	// it's just an Image operand, so there's no sampler descriptor data.
	if(getType(sampledImage).opcode() != spv::OpTypeSampledImage)
	{
		samplerId = Int(0);
	}

	uint32_t imageOperands = spv::ImageOperandsMaskNone;
	bool lodOrBias = false;
	Object::ID lodOrBiasId = 0;
	bool grad = false;
	Object::ID gradDxId = 0;
	Object::ID gradDyId = 0;
	bool constOffset = false;
	Object::ID offsetId = 0;
	bool sample = false;
	Object::ID sampleId = 0;

	uint32_t operand = (instruction.isDref() || instruction.samplerMethod == Gather) ? 6 : 5;

	if(insn.wordCount() > operand)
	{
		imageOperands = static_cast<spv::ImageOperandsMask>(insn.word(operand++));

		if(imageOperands & spv::ImageOperandsBiasMask)
		{
			lodOrBias = true;
			lodOrBiasId = insn.word(operand);
			operand++;
			imageOperands &= ~spv::ImageOperandsBiasMask;

			ASSERT(instruction.samplerMethod == Implicit);
			instruction.samplerMethod = Bias;
		}

		if(imageOperands & spv::ImageOperandsLodMask)
		{
			lodOrBias = true;
			lodOrBiasId = insn.word(operand);
			operand++;
			imageOperands &= ~spv::ImageOperandsLodMask;
		}

		if(imageOperands & spv::ImageOperandsGradMask)
		{
			ASSERT(!lodOrBias);  // SPIR-V 1.3: "It is invalid to set both the Lod and Grad bits." Bias is for ImplicitLod, Grad for ExplicitLod.
			grad = true;
			gradDxId = insn.word(operand + 0);
			gradDyId = insn.word(operand + 1);
			operand += 2;
			imageOperands &= ~spv::ImageOperandsGradMask;
		}

		if(imageOperands & spv::ImageOperandsConstOffsetMask)
		{
			constOffset = true;
			offsetId = insn.word(operand);
			operand++;
			imageOperands &= ~spv::ImageOperandsConstOffsetMask;
		}

		if(imageOperands & spv::ImageOperandsSampleMask)
		{
			sample = true;
			sampleId = insn.word(operand);
			imageOperands &= ~spv::ImageOperandsSampleMask;

			ASSERT(instruction.samplerMethod == Fetch);
			instruction.sample = true;
		}

		if(imageOperands != 0)
		{
			UNSUPPORTED("Image operands 0x%08X", imageOperands);
		}
	}

	Array<SIMD::Float> in(16);  // Maximum 16 input parameter components.

	uint32_t coordinates = coordinate.componentCount - instruction.isProj();
	instruction.coordinates = coordinates;

	uint32_t i = 0;
	for(; i < coordinates; i++)
	{
		if(instruction.isProj())
		{
			in[i] = coordinate.Float(i) / coordinate.Float(coordinates);  // TODO(b/129523279): Optimize using reciprocal.
		}
		else
		{
			in[i] = coordinate.Float(i);
		}
	}

	if(instruction.isDref())
	{
		auto drefValue = Operand(this, state, insn.word(5));

		if(instruction.isProj())
		{
			in[i] = drefValue.Float(0) / coordinate.Float(coordinates);  // TODO(b/129523279): Optimize using reciprocal.
		}
		else
		{
			in[i] = drefValue.Float(0);
		}

		i++;
	}

	if(lodOrBias)
	{
		auto lodValue = Operand(this, state, lodOrBiasId);
		in[i] = lodValue.Float(0);
		i++;
	}
	else if(grad)
	{
		auto dxValue = Operand(this, state, gradDxId);
		auto dyValue = Operand(this, state, gradDyId);
		ASSERT(dxValue.componentCount == dxValue.componentCount);

		instruction.grad = dxValue.componentCount;

		for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
		{
			in[i] = dxValue.Float(j);
		}

		for(uint32_t j = 0; j < dxValue.componentCount; j++, i++)
		{
			in[i] = dyValue.Float(j);
		}
	}
	else if(instruction.samplerMethod == Fetch)
	{
		// The instruction didn't provide a lod operand, but the sampler's Fetch
		// function requires one to be present. If no lod is supplied, the default
		// is zero.
		in[i] = As<SIMD::Float>(SIMD::Int(0));
		i++;
	}

	if(constOffset)
	{
		auto offsetValue = Operand(this, state, offsetId);
		instruction.offset = offsetValue.componentCount;

		for(uint32_t j = 0; j < offsetValue.componentCount; j++, i++)
		{
			in[i] = As<SIMD::Float>(offsetValue.Int(j));  // Integer values, but transfered as float.
		}
	}

	if(sample)
	{
		auto sampleValue = Operand(this, state, sampleId);
		in[i] = As<SIMD::Float>(sampleValue.Int(0));
	}

	auto cacheIt = state->routine->samplerCache.find(insn.resultId());
	ASSERT(cacheIt != state->routine->samplerCache.end());
	auto &cache = cacheIt->second;
	auto cacheHit = cache.imageDescriptor == imageDescriptor && cache.samplerId == samplerId;

	If(!cacheHit)
	{
		rr::Int imageViewId = *Pointer<rr::Int>(imageDescriptor + OFFSET(vk::SampledImageDescriptor, imageViewId));
		Pointer<Byte> device = *Pointer<Pointer<Byte>>(imageDescriptor + OFFSET(vk::SampledImageDescriptor, device));
		cache.function = Call(getImageSampler, device, instruction.parameters, samplerId, imageViewId);
		cache.imageDescriptor = imageDescriptor;
		cache.samplerId = samplerId;
	}

	Call<ImageSampler>(cache.function, texture, &in[0], &out[0], state->routine->constants);
}

SpirvShader::EmitResult SpirvShader::EmitImageQuerySizeLod(InsnIterator insn, EmitState *state) const
{
	auto &resultTy = getType(Type::ID(insn.resultTypeId()));
	auto imageId = Object::ID(insn.word(3));
	auto lodId = Object::ID(insn.word(4));

	auto &dst = state->createIntermediate(insn.resultId(), resultTy.componentCount);
	GetImageDimensions(state, resultTy, imageId, lodId, dst);

	return EmitResult::Continue;
}

SpirvShader::EmitResult SpirvShader::EmitImageQuerySize(InsnIterator insn, EmitState *state) const
{
	auto &resultTy = getType(Type::ID(insn.resultTypeId()));
	auto imageId = Object::ID(insn.word(3));
	auto lodId = Object::ID(0);

	auto &dst = state->createIntermediate(insn.resultId(), resultTy.componentCount);
	GetImageDimensions(state, resultTy, imageId, lodId, dst);

	return EmitResult::Continue;
}

SpirvShader::EmitResult SpirvShader::EmitImageQueryLod(InsnIterator insn, EmitState *state) const
{
	return EmitImageSample({ None, Query }, insn, state);
}

void SpirvShader::GetImageDimensions(EmitState const *state, Type const &resultTy, Object::ID imageId, Object::ID lodId, Intermediate &dst) const
{
	auto routine = state->routine;
	auto &image = getObject(imageId);
	auto &imageType = getType(image);

	ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
	bool isArrayed = imageType.definition.word(5) != 0;
	uint32_t dimensions = resultTy.componentCount - (isArrayed ? 1 : 0);

	const DescriptorDecorations &d = descriptorDecorations.at(imageId);
	auto descriptorType = routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);

	Pointer<Byte> descriptor = state->getPointer(imageId).base;

	Int width;
	Int height;
	Int depth;

	switch(descriptorType)
	{
	case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
	case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
		width = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, width));
		height = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, height));
		depth = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, depth));
		break;
	case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
		width = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, width));
		height = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, height));
		depth = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, depth));
		break;
	default:
		UNREACHABLE("Image descriptorType: %d", int(descriptorType));
	}

	if(lodId != 0)
	{
		auto lodVal = Operand(this, state, lodId);
		ASSERT(lodVal.componentCount == 1);
		auto lod = lodVal.Int(0);
		auto one = SIMD::Int(1);

		if(dimensions >= 1) dst.move(0, Max(SIMD::Int(width) >> lod, one));
		if(dimensions >= 2) dst.move(1, Max(SIMD::Int(height) >> lod, one));
		if(dimensions >= 3) dst.move(2, Max(SIMD::Int(depth) >> lod, one));
	}
	else
	{

		if(dimensions >= 1) dst.move(0, SIMD::Int(width));
		if(dimensions >= 2) dst.move(1, SIMD::Int(height));
		if(dimensions >= 3) dst.move(2, SIMD::Int(depth));
	}

	if(isArrayed)
	{
		dst.move(dimensions, SIMD::Int(depth));
	}
}

SpirvShader::EmitResult SpirvShader::EmitImageQueryLevels(InsnIterator insn, EmitState *state) const
{
	auto &resultTy = getType(Type::ID(insn.resultTypeId()));
	ASSERT(resultTy.componentCount == 1);
	auto imageId = Object::ID(insn.word(3));

	const DescriptorDecorations &d = descriptorDecorations.at(imageId);
	auto descriptorType = state->routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);

	Pointer<Byte> descriptor = state->getPointer(imageId).base;
	Int mipLevels = 0;
	switch(descriptorType)
	{
	case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
		mipLevels = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, mipLevels));  // uint32_t
		break;
	default:
		UNREACHABLE("Image descriptorType: %d", int(descriptorType));
	}

	auto &dst = state->createIntermediate(insn.resultId(), 1);
	dst.move(0, SIMD::Int(mipLevels));

	return EmitResult::Continue;
}

SpirvShader::EmitResult SpirvShader::EmitImageQuerySamples(InsnIterator insn, EmitState *state) const
{
	auto &resultTy = getType(Type::ID(insn.resultTypeId()));
	ASSERT(resultTy.componentCount == 1);
	auto imageId = Object::ID(insn.word(3));
	auto imageTy = getType(getObject(imageId));
	ASSERT(imageTy.definition.opcode() == spv::OpTypeImage);
	ASSERT(imageTy.definition.word(3) == spv::Dim2D);
	ASSERT(imageTy.definition.word(6 /* MS */) == 1);

	const DescriptorDecorations &d = descriptorDecorations.at(imageId);
	auto descriptorType = state->routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);

	Pointer<Byte> descriptor = state->getPointer(imageId).base;
	Int sampleCount = 0;
	switch(descriptorType)
	{
	case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
		sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount));  // uint32_t
		break;
	case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
		sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, sampleCount));  // uint32_t
		break;
	default:
		UNREACHABLE("Image descriptorType: %d", int(descriptorType));
	}

	auto &dst = state->createIntermediate(insn.resultId(), 1);
	dst.move(0, SIMD::Int(sampleCount));

	return EmitResult::Continue;
}

SIMD::Pointer SpirvShader::GetTexelAddress(EmitState const *state, Pointer<Byte> imageBase, Int imageSizeInBytes, Operand const &coordinate, Type const &imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect, OutOfBoundsBehavior outOfBoundsBehavior) const
{
	auto routine = state->routine;
	bool isArrayed = imageType.definition.word(5) != 0;
	auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
	int dims = coordinate.componentCount - (isArrayed ? 1 : 0);

	SIMD::Int u = coordinate.Int(0);
	SIMD::Int v = SIMD::Int(0);

	if(coordinate.componentCount > 1)
	{
		v = coordinate.Int(1);
	}

	if(dim == spv::DimSubpassData)
	{
		u += routine->windowSpacePosition[0];
		v += routine->windowSpacePosition[1];
	}

	auto rowPitch = SIMD::Int(*Pointer<Int>(descriptor + (useStencilAspect
	                                                          ? OFFSET(vk::StorageImageDescriptor, stencilRowPitchBytes)
	                                                          : OFFSET(vk::StorageImageDescriptor, rowPitchBytes))));
	auto slicePitch = SIMD::Int(
	    *Pointer<Int>(descriptor + (useStencilAspect
	                                    ? OFFSET(vk::StorageImageDescriptor, stencilSlicePitchBytes)
	                                    : OFFSET(vk::StorageImageDescriptor, slicePitchBytes))));
	auto samplePitch = SIMD::Int(
	    *Pointer<Int>(descriptor + (useStencilAspect
	                                    ? OFFSET(vk::StorageImageDescriptor, stencilSamplePitchBytes)
	                                    : OFFSET(vk::StorageImageDescriptor, samplePitchBytes))));

	SIMD::Int ptrOffset = u * SIMD::Int(texelSize);

	if(dims > 1)
	{
		ptrOffset += v * rowPitch;
	}

	SIMD::Int w = 0;
	if((dims > 2) || isArrayed)
	{
		if(dims > 2)
		{
			w += coordinate.Int(2);
		}

		if(isArrayed)
		{
			w += coordinate.Int(dims);
		}

		ptrOffset += w * slicePitch;
	}

	if(dim == spv::DimSubpassData)
	{
		// Multiview input attachment access is to the layer corresponding to the current view
		ptrOffset += SIMD::Int(routine->viewID) * slicePitch;
	}

	SIMD::Int n = 0;
	if(sampleId.value())
	{
		Operand sample(this, state, sampleId);
		if(!sample.isConstantZero())
		{
			n = sample.Int(0);
			ptrOffset += n * samplePitch;
		}
	}

	// If the out-of-bounds behavior is set to nullify, then each coordinate must be tested individually.
	// Other out-of-bounds behaviors work properly by just comparing the offset against the total size.
	if(outOfBoundsBehavior == OutOfBoundsBehavior::Nullify)
	{
		SIMD::UInt width = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, width));
		SIMD::Int oobMask = As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(u), width));

		if(dims > 1)
		{
			SIMD::UInt height = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, height));
			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(v), height));
		}

		if((dims > 2) || isArrayed)
		{
			UInt depth = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, depth));
			if(dim == spv::DimCube) { depth *= 6; }
			oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(w), SIMD::UInt(depth)));
		}

		if(sampleId.value())
		{
			Operand sample(this, state, sampleId);
			if(!sample.isConstantZero())
			{
				SIMD::UInt sampleCount = *Pointer<UInt>(descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount));
				oobMask |= As<SIMD::Int>(CmpNLT(As<SIMD::UInt>(n), sampleCount));
			}
		}

		constexpr int32_t OOB_OFFSET = 0x7FFFFFFF - 16;  // SIMD pointer offsets are signed 32-bit, so this is the largest offset (for 16-byte texels).
		static_assert(OOB_OFFSET >= MAX_MEMORY_ALLOCATION_SIZE, "the largest offset must be guaranteed to be out-of-bounds");

		ptrOffset = (ptrOffset & ~oobMask) | (oobMask & SIMD::Int(OOB_OFFSET));  // oob ? OOB_OFFSET : ptrOffset  // TODO: IfThenElse()
	}

	return SIMD::Pointer(imageBase, imageSizeInBytes, ptrOffset);
}

SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState *state) const
{
	auto &resultType = getType(Type::ID(insn.word(1)));
	auto imageId = Object::ID(insn.word(3));
	auto &image = getObject(imageId);
	auto &imageType = getType(image);

	Object::ID sampleId = 0;

	if(insn.wordCount() > 5)
	{
		int operand = 6;
		uint32_t imageOperands = insn.word(5);
		if(imageOperands & spv::ImageOperandsSampleMask)
		{
			sampleId = insn.word(operand++);
			imageOperands &= ~spv::ImageOperandsSampleMask;
		}
		// TODO(b/174475384)
		if(imageOperands & spv::ImageOperandsZeroExtendMask)
		{
			imageOperands &= ~spv::ImageOperandsZeroExtendMask;
		}
		else if(imageOperands & spv::ImageOperandsSignExtendMask)
		{
			imageOperands &= ~spv::ImageOperandsSignExtendMask;
		}

		// Should be no remaining image operands.
		if(imageOperands != 0)
		{
			UNSUPPORTED("Image operands 0x%08X", imageOperands);
		}
	}

	ASSERT(imageType.definition.opcode() == spv::OpTypeImage);
	auto dim = static_cast<spv::Dim>(imageType.definition.word(3));

	auto coordinate = Operand(this, state, insn.word(4));
	const DescriptorDecorations &d = descriptorDecorations.at(imageId);

	// For subpass data, format in the instruction is spv::ImageFormatUnknown. Get it from
	// the renderpass data instead. In all other cases, we can use the format in the instruction.
	auto vkFormat = (dim == spv::DimSubpassData)
	                    ? inputAttachmentFormats[d.InputAttachmentIndex]
	                    : SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(imageType.definition.word(8)));

	// Depth+Stencil image attachments select aspect based on the Sampled Type of the
	// OpTypeImage. If float, then we want the depth aspect. If int, we want the stencil aspect.
	auto useStencilAspect = (vkFormat == VK_FORMAT_D32_SFLOAT_S8_UINT &&
	                         getType(imageType.definition.word(2)).opcode() == spv::OpTypeInt);

	if(useStencilAspect)
	{
		vkFormat = VK_FORMAT_S8_UINT;
	}

	auto pointer = state->getPointer(imageId);
	Pointer<Byte> binding = pointer.base;
	Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + (useStencilAspect
	                                                                 ? OFFSET(vk::StorageImageDescriptor, stencilPtr)
	                                                                 : OFFSET(vk::StorageImageDescriptor, ptr)));

	auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));

	auto &dst = state->createIntermediate(insn.resultId(), resultType.componentCount);

	// VK_EXT_image_robustness requires replacing out-of-bounds access with zero.
	// TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
	auto robustness = OutOfBoundsBehavior::Nullify;

	auto texelSize = vk::Format(vkFormat).bytes();
	auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, sampleId, useStencilAspect, robustness);

	// Gather packed texel data. Texels larger than 4 bytes occupy multiple SIMD::Int elements.
	// TODO(b/160531165): Provide gather abstractions for various element sizes.
	SIMD::Int packed[4];
	if(texelSize == 4 || texelSize == 8 || texelSize == 16)
	{
		for(auto i = 0; i < texelSize / 4; i++)
		{
			packed[i] = texelPtr.Load<SIMD::Int>(robustness, state->activeLaneMask());
			texelPtr += sizeof(float);
		}
	}
	else if(texelSize == 2)
	{
		SIMD::Int offsets = texelPtr.offsets();
		SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(2, robustness);

		for(int i = 0; i < SIMD::Width; i++)
		{
			If(Extract(mask, i) != 0)
			{
				packed[0] = Insert(packed[0], Int(*Pointer<Short>(texelPtr.base + Extract(offsets, i))), i);
			}
		}
	}
	else if(texelSize == 1)
	{
		SIMD::Int offsets = texelPtr.offsets();
		SIMD::Int mask = state->activeLaneMask() & texelPtr.isInBounds(1, robustness);

		for(int i = 0; i < SIMD::Width; i++)
		{
			If(Extract(mask, i) != 0)
			{
				packed[0] = Insert(packed[0], Int(*Pointer<Byte>(texelPtr.base + Extract(offsets, i))), i);
			}
		}
	}
	else
		UNREACHABLE("texelSize: %d", int(texelSize));

	// Format support requirements here come from two sources:
	// - Minimum required set of formats for loads from storage images
	// - Any format supported as a color or depth/stencil attachment, for input attachments
	switch(vkFormat)
	{
	case VK_FORMAT_R32G32B32A32_SFLOAT:
	case VK_FORMAT_R32G32B32A32_SINT:
	case VK_FORMAT_R32G32B32A32_UINT:
		dst.move(0, packed[0]);
		dst.move(1, packed[1]);
		dst.move(2, packed[2]);
		dst.move(3, packed[3]);
		break;
	case VK_FORMAT_R32_SINT:
	case VK_FORMAT_R32_UINT:
		dst.move(0, packed[0]);
		// Fill remaining channels with 0,0,1 (of the correct type)
		dst.move(1, SIMD::Int(0));
		dst.move(2, SIMD::Int(0));
		dst.move(3, SIMD::Int(1));
		break;
	case VK_FORMAT_R32_SFLOAT:
	case VK_FORMAT_D32_SFLOAT:
	case VK_FORMAT_D32_SFLOAT_S8_UINT:
		dst.move(0, packed[0]);
		// Fill remaining channels with 0,0,1 (of the correct type)
		dst.move(1, SIMD::Float(0.0f));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_D16_UNORM:
		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
		dst.move(1, SIMD::Float(0.0f));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R16G16B16A16_UNORM:
		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
		dst.move(1, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
		dst.move(2, SIMD::Float(packed[1] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
		dst.move(3, SIMD::Float((packed[1] >> 16) & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
		break;
	case VK_FORMAT_R16G16B16A16_SNORM:
		dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
		dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
		dst.move(2, Max(SIMD::Float((packed[1] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
		dst.move(3, Max(SIMD::Float(packed[1] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
		break;
	case VK_FORMAT_R16G16B16A16_SINT:
		dst.move(0, (packed[0] << 16) >> 16);
		dst.move(1, packed[0] >> 16);
		dst.move(2, (packed[1] << 16) >> 16);
		dst.move(3, packed[1] >> 16);
		break;
	case VK_FORMAT_R16G16B16A16_UINT:
		dst.move(0, packed[0] & SIMD::Int(0xFFFF));
		dst.move(1, (packed[0] >> 16) & SIMD::Int(0xFFFF));
		dst.move(2, packed[1] & SIMD::Int(0xFFFF));
		dst.move(3, (packed[1] >> 16) & SIMD::Int(0xFFFF));
		break;
	case VK_FORMAT_R16G16B16A16_SFLOAT:
		dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
		dst.move(1, halfToFloatBits((As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFFFF0000)) >> 16));
		dst.move(2, halfToFloatBits(As<SIMD::UInt>(packed[1]) & SIMD::UInt(0x0000FFFF)));
		dst.move(3, halfToFloatBits((As<SIMD::UInt>(packed[1]) & SIMD::UInt(0xFFFF0000)) >> 16));
		break;
	case VK_FORMAT_R8G8B8A8_SNORM:
	case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
		dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
		dst.move(1, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
		dst.move(2, Max(SIMD::Float((packed[0] << 8) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
		dst.move(3, Max(SIMD::Float((packed[0]) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
		break;
	case VK_FORMAT_R8G8B8A8_UNORM:
	case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		dst.move(2, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		break;
	case VK_FORMAT_R8G8B8A8_SRGB:
	case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
		dst.move(0, ::sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
		dst.move(1, ::sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
		dst.move(2, ::sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		break;
	case VK_FORMAT_B8G8R8A8_UNORM:
		dst.move(0, SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		dst.move(2, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		break;
	case VK_FORMAT_B8G8R8A8_SRGB:
		dst.move(0, ::sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
		dst.move(1, ::sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
		dst.move(2, ::sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		break;
	case VK_FORMAT_R8G8B8A8_UINT:
	case VK_FORMAT_A8B8G8R8_UINT_PACK32:
		dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
		dst.move(1, (As<SIMD::UInt>(packed[0]) >> 8) & SIMD::UInt(0xFF));
		dst.move(2, (As<SIMD::UInt>(packed[0]) >> 16) & SIMD::UInt(0xFF));
		dst.move(3, (As<SIMD::UInt>(packed[0]) >> 24) & SIMD::UInt(0xFF));
		break;
	case VK_FORMAT_R8G8B8A8_SINT:
	case VK_FORMAT_A8B8G8R8_SINT_PACK32:
		dst.move(0, (packed[0] << 24) >> 24);
		dst.move(1, (packed[0] << 16) >> 24);
		dst.move(2, (packed[0] << 8) >> 24);
		dst.move(3, packed[0] >> 24);
		break;
	case VK_FORMAT_R8_UNORM:
		dst.move(0, SIMD::Float((packed[0] & SIMD::Int(0xFF))) * SIMD::Float(1.0f / 0xFF));
		dst.move(1, SIMD::Float(0.0f));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R8_SNORM:
		dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
		dst.move(1, SIMD::Float(0.0f));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R8_UINT:
	case VK_FORMAT_S8_UINT:
		dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
		dst.move(1, SIMD::UInt(0));
		dst.move(2, SIMD::UInt(0));
		dst.move(3, SIMD::UInt(1));
		break;
	case VK_FORMAT_R8_SINT:
		dst.move(0, (packed[0] << 24) >> 24);
		dst.move(1, SIMD::Int(0));
		dst.move(2, SIMD::Int(0));
		dst.move(3, SIMD::Int(1));
		break;
	case VK_FORMAT_R8G8_UNORM:
		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		dst.move(1, SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R8G8_SNORM:
		dst.move(0, Max(SIMD::Float((packed[0] << 24) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
		dst.move(1, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFF000000)) * SIMD::Float(1.0f / 0x7F000000), SIMD::Float(-1.0f)));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R8G8_UINT:
		dst.move(0, As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF));
		dst.move(1, (As<SIMD::UInt>(packed[0]) >> 8) & SIMD::UInt(0xFF));
		dst.move(2, SIMD::UInt(0));
		dst.move(3, SIMD::UInt(1));
		break;
	case VK_FORMAT_R8G8_SINT:
		dst.move(0, (packed[0] << 24) >> 24);
		dst.move(1, (packed[0] << 16) >> 24);
		dst.move(2, SIMD::Int(0));
		dst.move(3, SIMD::Int(1));
		break;
	case VK_FORMAT_R16_SFLOAT:
		dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
		dst.move(1, SIMD::Float(0.0f));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R16_UNORM:
		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
		dst.move(1, SIMD::Float(0.0f));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R16_SNORM:
		dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
		dst.move(1, SIMD::Float(0.0f));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R16_UINT:
		dst.move(0, packed[0] & SIMD::Int(0xFFFF));
		dst.move(1, SIMD::UInt(0));
		dst.move(2, SIMD::UInt(0));
		dst.move(3, SIMD::UInt(1));
		break;
	case VK_FORMAT_R16_SINT:
		dst.move(0, (packed[0] << 16) >> 16);
		dst.move(1, SIMD::Int(0));
		dst.move(2, SIMD::Int(0));
		dst.move(3, SIMD::Int(1));
		break;
	case VK_FORMAT_R16G16_SFLOAT:
		dst.move(0, halfToFloatBits(As<SIMD::UInt>(packed[0]) & SIMD::UInt(0x0000FFFF)));
		dst.move(1, halfToFloatBits((As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFFFF0000)) >> 16));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R16G16_UNORM:
		dst.move(0, SIMD::Float(packed[0] & SIMD::Int(0xFFFF)) * SIMD::Float(1.0f / 0xFFFF));
		dst.move(1, SIMD::Float(As<SIMD::UInt>(packed[0]) >> 16) * SIMD::Float(1.0f / 0xFFFF));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R16G16_SNORM:
		dst.move(0, Max(SIMD::Float((packed[0] << 16) & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
		dst.move(1, Max(SIMD::Float(packed[0] & SIMD::Int(0xFFFF0000)) * SIMD::Float(1.0f / 0x7FFF0000), SIMD::Float(-1.0f)));
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_R16G16_UINT:
		dst.move(0, packed[0] & SIMD::Int(0xFFFF));
		dst.move(1, (packed[0] >> 16) & SIMD::Int(0xFFFF));
		dst.move(2, SIMD::UInt(0));
		dst.move(3, SIMD::UInt(1));
		break;
	case VK_FORMAT_R16G16_SINT:
		dst.move(0, (packed[0] << 16) >> 16);
		dst.move(1, packed[0] >> 16);
		dst.move(2, SIMD::Int(0));
		dst.move(3, SIMD::Int(1));
		break;
	case VK_FORMAT_R32G32_SINT:
	case VK_FORMAT_R32G32_UINT:
		dst.move(0, packed[0]);
		dst.move(1, packed[1]);
		dst.move(2, SIMD::Int(0));
		dst.move(3, SIMD::Int(1));
		break;
	case VK_FORMAT_R32G32_SFLOAT:
		dst.move(0, packed[0]);
		dst.move(1, packed[1]);
		dst.move(2, SIMD::Float(0.0f));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
		dst.move(0, packed[0] & SIMD::Int(0x3FF));
		dst.move(1, (packed[0] >> 10) & SIMD::Int(0x3FF));
		dst.move(2, (packed[0] >> 20) & SIMD::Int(0x3FF));
		dst.move(3, (packed[0] >> 30) & SIMD::Int(0x3));
		break;
	case VK_FORMAT_A2R10G10B10_UINT_PACK32:
		dst.move(2, packed[0] & SIMD::Int(0x3FF));
		dst.move(1, (packed[0] >> 10) & SIMD::Int(0x3FF));
		dst.move(0, (packed[0] >> 20) & SIMD::Int(0x3FF));
		dst.move(3, (packed[0] >> 30) & SIMD::Int(0x3));
		break;
	case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
		dst.move(0, SIMD::Float((packed[0]) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
		dst.move(1, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
		dst.move(2, SIMD::Float((packed[0] >> 20) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
		dst.move(3, SIMD::Float((packed[0] >> 30) & SIMD::Int(0x3)) * SIMD::Float(1.0f / 0x3));
		break;
	case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
		dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
		dst.move(1, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
		dst.move(0, SIMD::Float((packed[0] >> 20) & SIMD::Int(0x3FF)) * SIMD::Float(1.0f / 0x3FF));
		dst.move(3, SIMD::Float((packed[0] >> 30) & SIMD::Int(0x3)) * SIMD::Float(1.0f / 0x3));
		break;
	case VK_FORMAT_R5G6B5_UNORM_PACK16:
		dst.move(0, SIMD::Float((packed[0] >> 11) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
		dst.move(1, SIMD::Float((packed[0] >> 5) & SIMD::Int(0x3F)) * SIMD::Float(1.0f / 0x3F));
		dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
		dst.move(3, SIMD::Float(1.0f));
		break;
	case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
		dst.move(0, SIMD::Float((packed[0] >> 10) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
		dst.move(1, SIMD::Float((packed[0] >> 5) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
		dst.move(2, SIMD::Float((packed[0]) & SIMD::Int(0x1F)) * SIMD::Float(1.0f / 0x1F));
		dst.move(3, SIMD::Float((packed[0] >> 15) & SIMD::Int(0x1)));
		break;
	case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
		dst.move(0, halfToFloatBits((packed[0] << 4) & SIMD::Int(0x7FF0)));
		dst.move(1, halfToFloatBits((packed[0] >> 7) & SIMD::Int(0x7FF0)));
		dst.move(2, halfToFloatBits((packed[0] >> 17) & SIMD::Int(0x7FE0)));
		dst.move(3, SIMD::Float(1.0f));
		break;
	default:
		UNSUPPORTED("VkFormat %d", int(vkFormat));
		break;
	}

	return EmitResult::Continue;
}

SpirvShader::EmitResult SpirvShader::EmitImageWrite(InsnIterator insn, EmitState *state) const
{
	imageWriteEmitted = true;

	auto imageId = Object::ID(insn.word(1));
	auto &image = getObject(imageId);
	auto &imageType = getType(image);

	ASSERT(imageType.definition.opcode() == spv::OpTypeImage);

	Object::ID sampleId = 0;

	if(insn.wordCount() > 4)
	{
		int operand = 5;
		uint32_t imageOperands = insn.word(4);
		if(imageOperands & spv::ImageOperandsSampleMask)
		{
			sampleId = insn.word(operand++);
			imageOperands &= ~spv::ImageOperandsSampleMask;
		}
		// TODO(b/174475384)
		if(imageOperands & spv::ImageOperandsZeroExtendMask)
		{
			imageOperands &= ~spv::ImageOperandsZeroExtendMask;
		}
		else if(imageOperands & spv::ImageOperandsSignExtendMask)
		{
			imageOperands &= ~spv::ImageOperandsSignExtendMask;
		}

		// Should be no remaining image operands.
		if(imageOperands != 0)
		{
			UNSUPPORTED("Image operands 0x%08X", (int)imageOperands);
		}
	}

	auto coordinate = Operand(this, state, insn.word(2));
	auto texel = Operand(this, state, insn.word(3));

	Pointer<Byte> binding = state->getPointer(imageId).base;
	Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
	auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));

	SIMD::Int packed[4];
	int texelSize = 0;
	auto format = static_cast<spv::ImageFormat>(imageType.definition.word(8));
	switch(format)
	{
	case spv::ImageFormatRgba32f:
	case spv::ImageFormatRgba32i:
	case spv::ImageFormatRgba32ui:
		texelSize = 16;
		packed[0] = texel.Int(0);
		packed[1] = texel.Int(1);
		packed[2] = texel.Int(2);
		packed[3] = texel.Int(3);
		break;
	case spv::ImageFormatR32f:
	case spv::ImageFormatR32i:
	case spv::ImageFormatR32ui:
		texelSize = 4;
		packed[0] = texel.Int(0);
		break;
	case spv::ImageFormatRgba8:
		texelSize = 4;
		packed[0] = (SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) |
		            ((SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) |
		            ((SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) |
		            ((SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24);
		break;
	case spv::ImageFormatRgba8Snorm:
		texelSize = 4;
		packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
		             SIMD::Int(0xFF)) |
		            ((SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
		              SIMD::Int(0xFF))
		             << 8) |
		            ((SIMD::Int(Round(Min(Max(texel.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
		              SIMD::Int(0xFF))
		             << 16) |
		            ((SIMD::Int(Round(Min(Max(texel.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) &
		              SIMD::Int(0xFF))
		             << 24);
		break;
	case spv::ImageFormatRgba8i:
	case spv::ImageFormatRgba8ui:
		texelSize = 4;
		packed[0] = (SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xff))) |
		            (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xff)) << 8) |
		            (SIMD::UInt(texel.UInt(2) & SIMD::UInt(0xff)) << 16) |
		            (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0xff)) << 24);
		break;
	case spv::ImageFormatRgba16f:
		texelSize = 8;
		packed[0] = floatToHalfBits(texel.UInt(0), false) | floatToHalfBits(texel.UInt(1), true);
		packed[1] = floatToHalfBits(texel.UInt(2), false) | floatToHalfBits(texel.UInt(3), true);
		break;
	case spv::ImageFormatRgba16i:
	case spv::ImageFormatRgba16ui:
		texelSize = 8;
		packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFFFF)) << 16);
		packed[1] = SIMD::UInt(texel.UInt(2) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0xFFFF)) << 16);
		break;
	case spv::ImageFormatRg32f:
	case spv::ImageFormatRg32i:
	case spv::ImageFormatRg32ui:
		texelSize = 8;
		packed[0] = texel.Int(0);
		packed[1] = texel.Int(1);
		break;
	case spv::ImageFormatRg16f:
		texelSize = 4;
		packed[0] = floatToHalfBits(texel.UInt(0), false) | floatToHalfBits(texel.UInt(1), true);
		break;
	case spv::ImageFormatRg16i:
	case spv::ImageFormatRg16ui:
		texelSize = 4;
		packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFFFF)) << 16);
		break;
	case spv::ImageFormatR11fG11fB10f:
		texelSize = 4;
		// Truncates instead of rounding. See b/147900455
		packed[0] = ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(0), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) >> 4) |
		            ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(1), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FF0)) << 7) |
		            ((floatToHalfBits(As<SIMD::UInt>(Max(texel.Float(2), SIMD::Float(0.0f))), false) & SIMD::UInt(0x7FE0)) << 17);
		break;
	case spv::ImageFormatR16f:
		texelSize = 2;
		packed[0] = floatToHalfBits(texel.UInt(0), false);
		break;
	case spv::ImageFormatRgba16:
		texelSize = 8;
		packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
		            (SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
		packed[1] = SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
		            (SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
		break;
	case spv::ImageFormatRgb10A2:
		texelSize = 4;
		packed[0] = (SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) |
		            ((SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 10) |
		            ((SIMD::UInt(Round(Min(Max(texel.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3FF)))) << 20) |
		            ((SIMD::UInt(Round(Min(Max(texel.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x3)))) << 30);
		break;
	case spv::ImageFormatRg16:
		texelSize = 4;
		packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) |
		            (SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF))) << 16);
		break;
	case spv::ImageFormatRg8:
		texelSize = 2;
		packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) |
		            (SIMD::UInt(Round(Min(Max(texel.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF))) << 8);
		break;
	case spv::ImageFormatR16:
		texelSize = 2;
		packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFFFF)));
		break;
	case spv::ImageFormatR8:
		texelSize = 1;
		packed[0] = SIMD::UInt(Round(Min(Max(texel.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(0xFF)));
		break;
	case spv::ImageFormatRgba16Snorm:
		texelSize = 8;
		packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
		            (SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
		packed[1] = (SIMD::Int(Round(Min(Max(texel.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
		            (SIMD::Int(Round(Min(Max(texel.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
		break;
	case spv::ImageFormatRg16Snorm:
		texelSize = 4;
		packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) & SIMD::Int(0xFFFF)) |
		            (SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF))) << 16);
		break;
	case spv::ImageFormatRg8Snorm:
		texelSize = 2;
		packed[0] = (SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) & SIMD::Int(0xFF)) |
		            (SIMD::Int(Round(Min(Max(texel.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F))) << 8);
		break;
	case spv::ImageFormatR16Snorm:
		texelSize = 2;
		packed[0] = SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7FFF)));
		break;
	case spv::ImageFormatR8Snorm:
		texelSize = 1;
		packed[0] = SIMD::Int(Round(Min(Max(texel.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(0x7F)));
		break;
	case spv::ImageFormatRg8i:
	case spv::ImageFormatRg8ui:
		texelSize = 2;
		packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF)) | (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0xFF)) << 8);
		break;
	case spv::ImageFormatR16i:
	case spv::ImageFormatR16ui:
		texelSize = 2;
		packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFFFF));
		break;
	case spv::ImageFormatR8i:
	case spv::ImageFormatR8ui:
		texelSize = 1;
		packed[0] = SIMD::UInt(texel.UInt(0) & SIMD::UInt(0xFF));
		break;
	case spv::ImageFormatRgb10a2ui:
		texelSize = 4;
		packed[0] = (SIMD::UInt(texel.UInt(0) & SIMD::UInt(0x3FF))) |
		            (SIMD::UInt(texel.UInt(1) & SIMD::UInt(0x3FF)) << 10) |
		            (SIMD::UInt(texel.UInt(2) & SIMD::UInt(0x3FF)) << 20) |
		            (SIMD::UInt(texel.UInt(3) & SIMD::UInt(0x3)) << 30);
		break;
	default:
		UNSUPPORTED("spv::ImageFormat %d", int(format));
		break;
	}

	// "The integer texel coordinates are validated according to the same rules as for texel input coordinate
	//  validation. If the texel fails integer texel coordinate validation, then the write has no effect."
	// - https://www.khronos.org/registry/vulkan/specs/1.2/html/chap16.html#textures-output-coordinate-validation
	auto robustness = OutOfBoundsBehavior::Nullify;

	auto texelPtr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, texelSize, sampleId, false, robustness);

	// Scatter packed texel data.
	// TODO(b/160531165): Provide scatter abstractions for various element sizes.
	if(texelSize == 4 || texelSize == 8 || texelSize == 16)
	{
		for(auto i = 0; i < texelSize / 4; i++)
		{
			texelPtr.Store(packed[i], robustness, state->activeStoresAndAtomicsMask());
			texelPtr += sizeof(float);
		}
	}
	else if(texelSize == 2)
	{
		SIMD::Int offsets = texelPtr.offsets();
		SIMD::Int mask = state->activeStoresAndAtomicsMask() & texelPtr.isInBounds(2, robustness);

		for(int i = 0; i < SIMD::Width; i++)
		{
			If(Extract(mask, i) != 0)
			{
				*Pointer<Short>(texelPtr.base + Extract(offsets, i)) = Short(Extract(packed[0], i));
			}
		}
	}
	else if(texelSize == 1)
	{
		SIMD::Int offsets = texelPtr.offsets();
		SIMD::Int mask = state->activeStoresAndAtomicsMask() & texelPtr.isInBounds(1, robustness);

		for(int i = 0; i < SIMD::Width; i++)
		{
			If(Extract(mask, i) != 0)
			{
				*Pointer<Byte>(texelPtr.base + Extract(offsets, i)) = Byte(Extract(packed[0], i));
			}
		}
	}
	else
		UNREACHABLE("texelSize: %d", int(texelSize));

	return EmitResult::Continue;
}

SpirvShader::EmitResult SpirvShader::EmitImageTexelPointer(InsnIterator insn, EmitState *state) const
{
	auto &resultType = getType(Type::ID(insn.word(1)));
	auto imageId = Object::ID(insn.word(3));
	auto &image = getObject(imageId);
	// Note: OpImageTexelPointer is unusual in that the image is passed by pointer.
	// Look through to get the actual image type.
	auto &imageType = getType(getType(image).element);
	Object::ID resultId = insn.word(2);

	ASSERT(imageType.opcode() == spv::OpTypeImage);
	ASSERT(resultType.storageClass == spv::StorageClassImage);
	ASSERT(getType(resultType.element).opcode() == spv::OpTypeInt);

	auto coordinate = Operand(this, state, insn.word(4));
	Object::ID sampleId = insn.word(5);

	Pointer<Byte> binding = state->getPointer(imageId).base;
	Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
	auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));

	// VK_EXT_image_robustness requires checking for out-of-bounds accesses.
	// TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
	auto robustness = OutOfBoundsBehavior::Nullify;

	auto ptr = GetTexelAddress(state, imageBase, imageSizeInBytes, coordinate, imageType, binding, sizeof(uint32_t), sampleId, false, robustness);

	state->createPointer(resultId, ptr);

	return EmitResult::Continue;
}

SpirvShader::EmitResult SpirvShader::EmitSampledImageCombineOrSplit(InsnIterator insn, EmitState *state) const
{
	// Propagate the image pointer in both cases.
	// Consumers of OpSampledImage will look through to find the sampler pointer.

	Object::ID resultId = insn.word(2);
	Object::ID imageId = insn.word(3);

	state->createPointer(resultId, state->getPointer(imageId));

	return EmitResult::Continue;
}

}  // namespace sw

redpajama_set_name: RedPajamaGithub


The Canadian Royal Mint created a coin with the face value of.Novelty Piggy Bank Back to School Gift Funny Gift Humor Vtg Bank Retro Coin. Pay your bill, manage your account, report an outage, and learn how to save energy. New Coins. A U.S. Mint spokesperson announced the plans for a new fifty-cent piece that was being issued in the honor of two great American patriots.
Never count your commemorative coins. famous people, movie stars, bits, humorous celebrities doing bits, funny.
AdToken (ADT) information, price quotes,. (coin) 0 ADT: 24h.
From stand-alone products to fully integrated solutions for analog and network infrastructures, find the right products for your security needs.Funny Coin Quotes - Funny Quotes about Coin - a little humor for your day from my large collection of funny quotes about life.
Get a constantly updating feed of breaking news, fun stories, pics, memes, and videos just for you. The Top 95 Most Hilarious Quotes About Money.95 funny and inspirational quotes about money.
Blessings Of Winter Fellings For You Flip A Coin God Put You In My Life F Having Then Leave I Gave.
Well, get ready for our own acknowledgeable list of funny customer support videos.


text:
Lily Cole Fronts BBC "CEO Secrets" Series After Running Company Into Ground
Who have the BBC got to front their new "CEO Secrets" series? Model, actor, and "entrepreneur" Lily Cole has been offering her "tips for business success":
"Believe in what you're doing and know why you're doing it, so it's very hard to run a business, and there's going to be up and down moments, and in those down moments what pulls you through is, you know, inner conviction of knowing why you're doing what you're doing and believing in it."
Inspiring stuff.
In other news, Lily's taxpayer-subsidised social network Impossible.com has reported losses of £256,000 in 2015 and £250,000 in 2014. That's despite taking a huge £200,000 grant from the Cabinet Office in 2013. The site achieved just 45,000 visitors last month. Please, Lily, tell us your secret…
mdi-timer 25th July 2016 @ 10:21 am 25th Jul 2016 @ 10:21 am mdi-comment Comments Before You Go Incognito…
It's gone midnight and before readers, er, go incognito, they might be interested to learn the government is going to make it harder. DCMS today launch a public consultation to require porn websites to ensure all their viewers are over 18. The plan is that Jack Dromey et al will have to sign in to an identify provider such as their bank or mobile operator before they open up the "private browsing" section. Sites that do not abide by the new law will face civil action or even be blocked, Chinese-style, which seems unworkable at best and draconian censorship at worst. No technology has been or ever will be invented that can stop teenage boys looking at pictures of naked girls…
mdi-timer 16th February 2016 @ 12:01 am 16th Feb 2016 @ 12:01 am mdi-comment Comments Engineers Move Objects Using 'The Force'
Star Wars fans will be pleased to hear that they are one step closer to being able to use 'the force'. The BBC has revealed that a team of engineers have designed a mechanism that can move and hold pea-sized objects from 30cm to 40cm away through the power of "holograms" made of sound waves. The pretty cool video above shows how the holograms manipulate objects, finishing with a "cardboard UFO" circling the speaker grid to show its "tractor beam" capability. A development most interesting it is…
mdi-timer 28th October 2015 @ 2:35 pm 28th Oct 2015 @ 2:35 pm mdi-comment Comments
Boris' Broadband Scoreboard
Boris has launched a programme that will rank buildings in London by their connectivity and help businesses understand whether offices will meet their internet needs. Any building that signs up to the Connectivity Ratings Scheme will receive a technical assessment from WiredScore, who run similar programmes across major US cities, and will be ranked against other London buildings in a searchable database.
There is staggering variability in the the quality of broadband connections across London and a culture of property owners not being upfront about just how bad the connectivity in their building is. By creating a voluntary database, Boris hopes to force landlords to compete against each other to make their properties more attractive to tenants. Now to rank them by proximity to Nandos…
mdi-timer 23rd October 2015 @ 11:02 am 23rd Oct 2015 @ 11:02 am mdi-comment Comments Taxpayers 1-0 Microsoft
The Crown Commercial Service has signed a deal with an open source software company called Collabora Productivity that will make the Libre Office software available across all government departments. Libre Office is a free version of Microsoft Office, a software package that the government spends millions in license fees to use. Collabora will provide a specially tailored version of Libre Office for free and will provide technical assistance and support.
The CCS deal is their latest move in a long running campaign to stamp out the public sector culture of mindlessly funnelling taxpayer money to big software companies and comes on the back of Government Digital Service's victory in forcing Microsoft into supporting Open Document Formats. Libre Office uses the ODF standard and by making Microsoft support the format, CCS have opened the door for a seamless switch to free opensource software such as Libre Office. Don't expect Microsoft to go down without a fight…
mdi-timer 21st October 2015 @ 3:33 pm 21st Oct 2015 @ 3:33 pm mdi-comment Comments Uber Victory: High Court Rules App Not Illegal
Mr Justice Ouseley rules that a smart phone or other GPS device does not equal a taxi-meter, representing a win for Uber
— Ben Ando (@BenAndo) October 16, 2015
The ruling clarifies that Uber's smartphone app isn't breaking the law as it isn't operating in the same way as the regulated meters used by black cabs to calculate fares. The cabbies will be furious…
UPDATE: The luddites have already appealed
Unbelievable! High Court says it's NOT a meter! LTDA have lodged appeal to Supreme Court
— The LTDA (@TheLTDA) October 16, 2015
UPDATE II: Uber have responded
"This is great news for Londoners and a victory for common sense. Now the High Court has ruled in favour of new technology, we hope Transport for London will think again on their bureaucratic proposals for apps like Uber. Compulsory five-minute waits and banning ride-sharing would be bad for riders and drivers. These plans make no sense. That's why 130,000 people have already signed our petition against these proposals. We hope TfL will listen to Londoners and let Uber keep London moving."
mdi-timer 16th October 2015 @ 10:22 am 16th Oct 2015 @ 10:22 am mdi-comment Comments Previous Page Next Page

redpajama_set_name: RedPajamaCommonCrawl


NHI Bill being pushed for elections?
The South African NCDs Alliance (SANCDA) and its NCDs partners are celebrating a pivotal win with the creation of a national NCDs coordinating body. In July after four years of consistent advocacy, the South African National Health Commission (SANHC) was created.
It marks an advocacy tipping point with the official acknowledgement of NCDs as the leading class of disease mortality in South Africa. At last, there is parity for NCDs with HIV/AIDS and TB. Well, at least on the co-ordination continuum. More successes along the lines of achieved for the MDG communicable diseases are needed.
The SANHC is one of the institutions created to implement and coordinate the South African version of universal health coverage and access, National Health Insurance (NHI). The NHI is in the second phase of the rollout which will target on vulnerable groups: mother, child, school health, elderly and disabled.
Plans for a SANHC were outlined by the National Department of Health in early 2013 with implementation due the following year. Initially, its scope was to address only "social determinants" and their prevention. From 2014 onward the SANCDA advocated for a wider scope that included NCDs prevention and treatment in a co-ordinated multistakeholder and multisectoral approach. This whole of government and whole of society context is critical for complex societal and health problems as addressed by the United Nations's transformational 2030 Sustainable Development Agenda. The SA National Development Plan (2011) is a visionary precursor.
By the end of the end of 2014 all the activity culminated in a meeting with the Deputy Minister of Health where the SANCDA once more called for the swift formation of this high-level body.
The SANCDA's 2015 Civil Society Status Report underlined it as a major element necessary to combat NCDs and lamented the lack of action. There was a ray of hope by later in that year with the proposed link to the SANHC to NHI. The 2015 NHI White Paper (1st version) mentioned the creation of a SANHC but still with a very limited scope which was a key focus area for reform and contestation. The SANCDA in its written comments reiterated its call for a national NCDs co-ordinating body as framed by the Sustainable Development Goals.
In July 2017 a raft of NHI related policy was published including the NHI White Paper (2nd version) plus the formation of seven NHI implementation institutions. There was little change to the SANHC scope and the objectives. However, a swift draft revision was circulated (text box 1) in the SANHC serves as the guardian of NCDs prevention and care. The SANCDA awaits official confirmation of the objectives and structure.
And, as a show of good faith, has nominated SANCDA director, Dr Vicki Pinkney-Atkinson, as a civil society representative. The SANCDA will report on further developments.
a. Identify the social & economic factors that drive premature illness and death from NCDs.
b. Interrogate the means & mechanisms through which these determinants can be addressed, including the interventions required from different government departments and non-state actors.
c. Utilise scientific evidence on the causes of NCDs and how to prevent these. Based on this information draw up feasible and implementable plans to promote health and prevent diseases through interventions by the relevant stakeholders.
d. Research & utilise international best practice on health promotion and disease prevention interventions across sectors, analyse these for their feasibility and relevance to South Africa and make recommendations on implementation through SANHC to member government departments and non-state actors.
e. Periodically analyse surveillance data on NCDs and adapt strategies to changing patterns.
f. Analyse cost-effectiveness and cost-benefit of interventions to reduce NCDs and ensure the most effective and efficient use of resources across sectors.
g. Assist government departments and non-state actors to draw up strategic and operational plans that will positively impact on the social determinants of health.
h. Consider and provide input into strategic and operational plans drawn up by government departments and other non-state actors vis-à-vis objectives and activities aimed at promoting health and preventing disease.
i. Monitor the implementation of the plans and activities of all sectors with regards to the plans submitted to redress the social determinants of health.
j. Evaluate existing interventions aimed at the promotion of health & the prevention of illness as well as programmes and projects that derive from the SANHC and make applicable recommendations to the relevant department or non-state actors.
k. Ensure collaboration between and across government and non-state actors including non-government organizations, academia, representatives of labour and the private sector, to systematically improve the health status of South Africans and reduce the need for healthcare interventions.
m. Where circumstances permit, the SANHC may act as a conduit for channelling funding to relevant sectors dealing with the social determinants of health.
n. Co-ordinate sectors synergistically & eliminate wasteful duplication.
[i] This draft revision awaits official confirmation.


This comfortable apartment on the fourth floor is in a residential building in Makarska. A steep spiral staircase leads to the roof, where the ceiling height is minimum 100 cm. The apartment has two bedrooms, a bathroom, a toilet and a kitchen with living area from where you can reach the terrace. The city centre, the long beach, many restaurants and bars are within easy walking distance. Day trips by boat to the islands of Hvar and Brac are recommended.


text:
Our collective voice can make a difference
Donate to a campaign
Join a movement - stand up for change.
Sadly, not only is our precious environment and its wildlife suffering, but there are people fighting for their rights and their lives across the globe. But there is hope...
We must lobby governments, businesses and decision-makers. Together, we have the power to bring about real change. When enough people add their voice to a collective call for action, businesses and political leaders will be forced to pay attention.
Act against dolphin killing and shark finning
Taiwan must act
Stand up for the rights of climate refugees
Protect climate refugees
TELL UK SUPERMARKETS TO COMMIT TO SLAVERY-FREE SEAFOOD
SIGN OUR LETTER


text:
Q: Unity Facebook SDK: Dialogs Cut Off When I show the Share or Send Request dialog from my Unity app on Android, they seem to be cut off at the top.

There is a question about exactly the same issue using the regular (Java) Facebook Android SDK: Dialog on Android KitKat seems to be cut, but all of the solutions there require direct access to the Java classes.
Has anyone seen this issue with the Facebook Unity SDK? Is there a way to fix this, apart from using the Java SDK instead of the Unity SDK?
I'm using Unity 4.6.3 and version 6.2.2 of the SDK.

redpajama_set_name: RedPajamaStackExchange


text:
What's up for the Internet in 2003?
Tom Spring
Eat your heart out, Miss Cleo. Our forecast for the Internet in 2003 is based on much more than psychic insight or a crystal ball.
Among the predictions: faster, more reliable service, both wired and wireless; monthly dial-up charges that go up as the volume of spam goes down; and gadgets like a wristwatch through which your spouse reminds you to pick up a quart of milk on your way home.
Clearly, the Internet has more in store for us than spy-camera pop-up ads and tribute Web sites to rapper Eminem.
Bandwidth's Long Boom
Broadband Internet access into the home will continue to drive Internet adoption in 2003, said Jed Kolko, senior analyst at Forrester Research Inc. Whether in search of faster Web browsing or the capability to link a growing cadre of entertainment devices, more of us will sign up for high-speed Net access at home in 2003.
By this time next year, 23.3 million households will have broadband connections, according to an EMarketer Inc. report. That's a 38 percent jump from the 16.8 million broadband-equipped households in the United States today.
Give it another year, and broadband users will overtake the number of dial-up customers in 2004, Kolko said.
If you haven't switched by then, you'll get a financial push to do so: Dial-up access will jump as high as US$40 monthly in 2004, said Vernon Keenan, Internet analyst with Keenan Vision Inc.
"The real cost of bandwidth is going to start to hit the wallets of dial-up users," Keenan said. Higher dial-up cost won't impact broadband users, who already pay a premium for higher speeds, he said.
Why higher dial-up prices? The telecom meltdown that drove dozens of Internet backbone providers out of business and into bankruptcy will finally be billed to consumers, Keenan said. Also, broadband may become more inviting when it bans spam; as backbone providers start skimping on bandwidth, they may be motivated to block the massive amounts of junk e-mail that sap much of their network capacity.
Also, Internet access will take flight, whether from your living room or a city block. Wireless technology – Wi-Fi, or 802.11 – is among the most promising for 2003, according to analysts.
Soon you'll be able to connect wirelessly in many more places, thanks to Wi-Fi companies like Cometa Networks and Vivato Inc.
AT&T Corp., IBM Corp., and Intel Corp. recently jointly launched Cometa, hoping in 2003 to make wireless Internet access as commonplace as Starbucks in Seattle (which, incidentally, is also a hotbed of hot spots).
By the end of 2003, Cometa expects to have about half-completed its network, rolling out 5,000 Wi-Fi hot spots in 50 U.S. metropolitan areas, said Steve Harris, Cometa's vice president of corporate affairs. By 2004, the company wants hot spots to be so common in those 50 markets that you will never be more than a five-minute walk from wireless Internet access.
Meanwhile, a start-up named Vivato is working on 802.11 antenna technology that boosts the range of a Wi-Fi hot spot from the current 300 feet to as far as 4 miles.
Couple Vivato technology with Cometa and a number of burgeoning Wi-Fi initiatives like service provider Boingo Wireless Inc., and the result resembles a cellular network, said Howard Locker, chief architect for IBM client systems.
On the device side, semiconductor giant Intel plans to unveil in 2003 a wireless-enabled chip, code-named Banias, that integrates Wi-Fi capability into notebooks and other mobile devices. Within three years, as many as 30 million laptops and gadgets could be wired for Wi-Fi, Intel estimates.
Locker said 2003 will be the year of trial hot-spot business models, as many new services test consumers' appetite for fee-based services. Airports, for example, will charge their captive customers. Meanwhile, a cafe might offer free access as an extra lure.
The Net Begets the Gadget
Thanks to faster, more reliable wireless Internet access, whether next-generation cellular or Wi-Fi, networks will handle more sophisticated tasks.
Cometa's Harris expects such applications as fast-food restaurants accepting orders placed through Wi-Fi-enabled PDAs (personal digital assistants) instead of the drive-through intercom. Or when you hear a song you like on the car radio and you're in a Cometa Wi-Fi hot spot, you can download the entire CD to a digital media player in the car.
"Devices will evolve and so will the applications on those devices," said John Ankcorn, principal research scientist at Hewlett-Packard Co.'s Hewlett-Packard Labs. Devices will be location-aware, bandwidth-smart, and able to adapt to your needs, he said.
The next killer app for the wireless Internet is the location-based community, said Hank Nothhaft, chief executive officer of device maker Danger Inc. In 2003, new services will let you rate your neighborhood pizza parlor the same way you rate a seller on EBay or a product on Amazon.com, Nothhaft said.
"If the pizza stinks, a location-based service will allow you to rate the food so anyone walking by will be forewarned," Nothhaft said.
Promoting these new functions will be wireless prices that come down from the stratosphere. Look for wireless data plans to debut in 2003 priced at about US$15 monthly for 10MB of data, Nothhaft predicted. Monthly fees today run about US$40.
"Wireless Internet only becomes ubiquitous when service plans are affordable," agreed Michael Gartenberg, research director at Jupiter Research.
Keeping Things in Context
Once wireless-data prices drift down, we will see a proliferation of location-based services married with relevant data, Gartenberg said. He envisions a car device that provides voice-enabled driving directions by pulling data from the Net, a PDA that offers automobile price comparisons because you're at a car dealership, or a cell phone that links to your bank account so you can tell whether you can afford that new projection screen TV.
Wristwatch maker Fossil Inc. is working on a PDA wristwatch that can connect to a cellular network. Along with PDA functions, the Fossil wristwatch will support text messaging so you can receive a message anytime, anywhere, via your wrist — no clunky PDA required, said Donald Brewer, Fossil's vice president of technology.
Microsoft has been tight-lipped about its network technology called Smart Personal Object Technology (SPOT). However, at a recent technology conference, Microsoft Chairman Bill Gates teased the audience with a few hints.
In 2003, Microsoft will push SPOT technology that uses a wireless Internet connection to automatically update everything from keychains to refrigerator magnets to wristwatches with contextually relevant information, according to Gates. For example, Microsoft describes an alarm clock with an online link to an atomic clock and weather feeds so you know exactly what the time and weather are before you get out of bed. Gartenberg goes further, saying that by 2004 our daily routine will be filled with "smart objects" that have been enhanced with contextually relevant information.
In 2003 we may still be decades away from creating the kind of interaction between computers, the Internet, and people that is portrayed every summer by Hollywood. The ubiquitous Internet may not yet be real, but the new technology won't be boring.
Lost Packets
Cisco takes aim at new competitors
Microsoft deepens partnership with OpenAI


If you are looking for a decadent escape in one the finest historic buildings in the old city then The Milk Thistle is the perfect place. The hippest prohibition bar and a younger sister of Hyde & Co it is priding itself on being purveyor of the finest cocktails in the city, and with four floors, including a cocktail bar, lounge and private function rooms is the perfect place for a fabulous party. To view their gift vouchers, click here.
Hyde&Co, 2 The Basement, Upper Byron Pl. Bristol, BS8 1JY uses Vouchermine, a trusted 3rd party provider to manage and fulfil our voucher facility.


Humans are complex, with a range of emotions, beliefs and needs. Often, there is conflict when one person's characteristics clash with another's. When there is a clash with someone you work with, it presents a problem that has to be dealt with.
Conflict is normal in relationships; differences of perception, interpretation of events and opinion are inevitable. It is not conflict that damages relationships, but the refusal or inability to deal with it that is the problem.
According to the Thomas Killman Model, there are five strategies that can be used to manage conflict. It must be stressed that no strategy is in itself right or wrong. It may, however, be more or less applicable in certain circumstances.
This strategy results from a high concern for your group's own interests with less concern for others. The outcome is win or lose.
This strategy includes attempts at bargaining. It is generally used when basic rights are at stake or to set a precedent.
However, it can cause the conflict to escalate and losers may try to retaliate.
Against people who take advantage of non-competitive behaviour.
This results from a high concern for your group's own interests, matched with a high concern for the interests of other partners. This results in a "win-win" outcome.
It is also generally the best strategy when society's interest is at stake. This approach helps to build commitment and reduce bad feelings.
The drawbacks are that it takes time and energy. In addition, some partners may take advantage of the others' trust and openness. Generally regarded as the best approach for managing conflict, the objective of collaboration is to reach consensus.
To work through feelings that have interfered with a relationship.
This strategy results from a high concern for your group's own interests along with a moderate concern for the interests of other partners. The outcome is "win some or lose some".
This strategy is generally used to achieve temporary solutions, to avoid destructive power struggles or when time pressures exist.
One drawback is that partners can lose sight of important values and long-term objectives. This approach can also distract the partners from the merits of an issue and create a cynical climate.
To arrive at expedient solutions under time pressure.
This results from a low concern for your group's own interests coupled with a low concern for the interests of others. This results in a "lose-lose" outcome.
This strategy is generally used when the issue is trivial or other issues are more pressing. It is also used when confrontation has a high potential for damage or more information is needed.
It may be beneficial for both parties to shelve the problem till the climate changes. This allows both parties to maintain cordial relationships in the short to medium term.
The drawback is that important decisions may be made by default.
When gathering information supersedes immediate decisions.
This results from a low concern for your group's own interests combined with a high concern for the interests of other partners. This results in a "win-or-lose" outcome.
This is generally used when the issue is more important to others than to you. It is a goodwill gesture and is appropriate when you recognise that you are in the wrong.
The drawbacks are that your own ideas and concerns don't get attention. You may also lose credibility and future influence.
When harmony and stability are especially important.


• Acquittal of client, a practicing lawyer, of all charges in a 6-month federal Racketeering & Securities Fraud jury trial.
• CEO of Manufacturing Company - Philadelphia U.S. Attorney dismissed all charges after Federal Jury Trial in which client was tried on bank fraud charges.
--Mail fraud, money laundering, and tax evasion case.
that post, in civil matters.
A graduate of Georgetown Law School, Howard serves as an adjunct Professor of Evidence and Trial Advocacy at Temple University Law School, and conducts training programs at law firms and government agencies for ALI-ABA in trial advocacy, deposition practice, motions and oral advocacy and evidence.
Howard is a frequent lecturer on topics relating to the criminal justice system and litigation practice. He is the author of the Deposition Guidebook (ALI-ABA 2007), as well as numerous articles relating to the field of litigation, and is a member of the Editorial Board of the Practical Litigator.
Philadelphia, Federal (Chairman, Criminal Law Committee, 1987-1995) and American Bar Associations.


So tomorrow will be 31 weeks. Little Willow has been swimming around and honing her soccer skills. I have been feeling pretty good except for the occasional heart burn. Next week is my shower and I really need to work on her room and the house this week!!!


text:
There were people for and against slavery in Michigan before it was completely banned by the 13th Amendment to the United States Constitution. You can read a quick history about those who opposed slavery in Michigan below.
The Northwest Ordinance makes slavery illegal its territories and states. Although Michigan is part of the Northwest Territory, there are enslaved people living in Michigan until 1837.
Thornton and Lucie Blackburn free themselves from slavery in Kentucky and arrive in Detroit.
Elizabeth Chandler starts the first anti-slavery society in Michigan. Laura Haviland also joins the society.
African-Americans form the Second Baptist Church in Detroit, which was an important stop on the Underground Railroad.
Michigan becomes a state. Michigan's Constitution bans slavery.
Henry Bibb, who freed himself from slavery, arrives in Michigan. He begins telling about the terrible ways enslaved people are treated in the South.
Raiders from Kentucky come to Young's Prairie in Cass County and try to kidnap at least nine formerly enslaved people.
Adam Crosswhite and his family escaped from slavery, a system by which a person is forced to work without pay and doesn't have freedom, in Kentucky. They traveled north and settled near Marshall, Michigan. Adam feared that slave catchers from Kentucky might come to Michigan… Read More
The Michigan State Legislature passes a Personal Liberty Act that makes it difficult for slave catchers to kidnap formerly enslaved people in Michigan.
Abolitionist and former enslaved woman Sojourner Truth moves to Battle Creek, Michigan.
President Abraham Lincoln issues the Emancipation Proclamation freeing enslaved African-Americans in the Confederacy, the group of states which seceded from the United States.
The First Michigan Colored Infantry Regiment leaves Detroit to fight in the Civil War.
The 13th Amendment of the United States Constitution bans slavery.
Teaching the Underground Railroad
The Underground Railroad is an important aspect of U.S. history. It allows us to explore in depth the institution of slavery and the search for freedom by runaway slaves and their allies. It is one of the most important examples in our history of individuals… Read More


How I Quit: Karen K. @ Quit With Us, Louisiana!
How I Quit: Karen K.
I made the decision that 2014 would be a year that I would focus on my health. I'm 29 years old and want to lead a healthy lifestyle. The first choice I made was to quit smoking. I started Chantix in December of 2013 and set my quit date. December 19, 2013 started a new journey for me. Chantix worked for me, but after a few weeks I noticed side effects that I was concerned about. With the advice of my doctor, I stopped taking Chantix, but have continued on the no smoking journey. Today I celebrate 3 months of being smoke free. I never in a million years thought I could do this and stick to it. Each day is a new day and each day gets a little easier. What's made this time a success is very simple. I made the decision to quit smoking. No one else made it for me. All of the quit smoking adds, ex smokers telling me that I should quit, even my doctor telling me all of the scary statistics didn't work. I had to make the decision for myself. When I go to bed after another successful day, reach a new milestone, or even just make it through a situation that would usually include a cigarette, I do a little happy dance. My decision to be smoke free was the best decision I've made in my life.


The Micro+ 3D printer is ready to help spark ideas and bring them to life. With a compact 7.3" - cube design, the Micro+ is the perfect choice for any room or environment. Want to take it on the go? Weighing only 2.3lbs, take your talents with you at any time. The Micro+ is the best choice for getting started in 3D printing, and is a perfect printer for kids and adults to use.


text:
<ion-header>
  <ion-navbar>
  <ion-title>
    Treinamento
  </ion-title>
    <ion-buttons end>
      <button (click)="presentFilter()">
        <ion-icon ios="ios-options-outline" md="md-options"></ion-icon>
      </button>
    </ion-buttons>
  </ion-navbar>
</ion-header>

<ion-content class="training-choose">

  <ion-card>
    <ion-list text-wrap>
      <button ion-item (click)="goToGameNote()">
        Notas musicais
      </button>

      <button ion-item (click)="goToGameChord()">
        Acordes
      </button>

      <button ion-item (click)="goToRecords()">
        Visualizar Records
      </button>

    </ion-list>
  </ion-card>
</ion-content>


The Death of the Church?
The former Rector of the Shrine of the Holy Face in Manoppello, Servant of God Padre Domenico da Cese, firmly believed with all his heart that, like the Shroud of Turin, the Holy Veil of Manoppello was one of the many burial cloths in Jesus's tomb — the holy sudarium which covered the Face of Jesus in death–and also miraculously bears witness to His Resurrection. An incredible claim, to be sure, but one for which Padre Domenico offered his own suffering and death.
Since the pilgrimage by Pope Benedictict XVI to the shrine in 2006, the veil of the Face of Christ has become more widely known after having been hidden away in the Abruzzo Mountains for centuries. Other pilgrims who have seen and pondered the "Il Volto Santo" have contemplated the significance of this particular image of the Face of Jesus, and it's message for the Church and the world. The Face on the Holy Veil is unique above all images of the Face of Christ in many ways, but especially for the fact that it records, in a miraculous way, on byssus silk, not only the Passion of Jesus, but the first breath of His Resurrection. Therein, I believe, lies the message of this holy image for our tumultuous times.
The Catholic Church has been mortally wounded by scandal upon scandal recently, and may be only just at the beginning of its death throes. But, this would not be the first death of the Faith, as author G.K.Chesterton pointed out nearly a century ago. Lauren Enk Mann has written an excellent essay on Catholic World Report, The Sixth Death of the Church, which gives us reason for hope–if. If we are prepared as a Church to take courage and suffer together with Christ in His Passion in order to share in His Resurrection.
If you would like to learn more about the Veil of Manoppello – Paul Badde's new book The Holy Veil of Manoppello: The Human Face of God may now be pre-ordered on Amazon. The book is set to be released in October, 2018.
I have the book! If u want it!
So kind of you to offer, Marcia, but I ordered several which should be here soon…and I can work on patience in the meantime. 😉 God bless!
Hi, Patricia. I have just had some good news with regard to my own little family's response to the crisis. Sorry to be so mysterious but I want to write a post about it and I don't want to spoil it for you. God has done something wonderful for us. All the faithful are suffering so much these days but God hasn't abandoned us. My little story shows that He will provide for us if we persevere.


text:
Q: Hide internet connection bar after five seconds in Flutter I am a beginner in a Flutter, and I watched a YouTube video about adding the internet connection verification bar, but it is fixed and does not disappear, how can I hide it after a specified time.
This is the connection bar!

Builder(
    builder: (BuildContext context) {
      return OfflineBuilder(
        connectivityBuilder: (BuildContext context,
            ConnectivityResult connectivity, Widget child) {
          final bool connected =
              connectivity != ConnectivityResult.none;
          return Stack(
            fit: StackFit.expand,
            children: [
              child,
              Positioned(
                left: 0.0,
                right: 0.0,
                height: 32.0,
                child: AnimatedContainer(
                  duration: const Duration(milliseconds: 300),
                  color:
                  connected ? Color.fromRGBO(46, 204, 113, 1) : Color.fromRGBO(231, 76, 60, 1),
                  child: connected
                      ?  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        "Online",
                        style: TextStyle(color: Colors.white),
                      ),

                    ],
                  )
                      : Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(
                        "Offline",
                        style: TextStyle(color: Colors.white),
                      ),
                      SizedBox(
                        width: 8.0,
                      ),
                      SizedBox(
                        width: 12.0,
                        height: 12.0,
                        child: CircularProgressIndicator(
                          strokeWidth: 2.0,
                          valueColor:
                          AlwaysStoppedAnimation<Color>(
                              Colors.white),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          );
        },

      );
    },
  ),

I put the code, and this is the video I watched!
Can anyone modify the code to make it work as I want it to?

A: You can copy paste run full code below
You can wrap Positioned with Visibility and set visible to false after some time
code snippet
_hideBar() {
    Timer(Duration(seconds: 5), () {
      setState(() {
        _visible = false;
      });
    });
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _hideBar();
    });
  }

...

Visibility(
                visible: _visible,
                child: Positioned(
                  height: 32.0,

working demo

full code
import 'package:flutter/material.dart';
import 'package:flutter_offline/flutter_offline.dart';
import 'dart:async';

class DemoPage extends StatefulWidget {
  @override
  _DemoPageState createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  bool _visible = true;
  _hideBar() {
    Timer(Duration(seconds: 5), () {
      setState(() {
        _visible = false;
      });
    });
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _hideBar();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Offline Demo"),
      ),
      body: OfflineBuilder(
        connectivityBuilder: (
          BuildContext context,
          ConnectivityResult connectivity,
          Widget child,
        ) {
          final bool connected = connectivity != ConnectivityResult.none;
          return Stack(
            fit: StackFit.expand,
            children: [
              child,
              Visibility(
                visible: _visible,
                child: Positioned(
                  height: 32.0,
                  left: 0.0,
                  right: 0.0,
                  child: AnimatedContainer(
                    duration: const Duration(milliseconds: 350),
                    color: connected ? Color(0xFF00EE44) : Color(0xFFEE4400),
                    child: AnimatedSwitcher(
                      duration: const Duration(milliseconds: 350),
                      child: connected
                          ? Text('ONLINE')
                          : Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: <Widget>[
                                Text('OFFLINE'),
                                SizedBox(width: 8.0),
                                SizedBox(
                                  width: 12.0,
                                  height: 12.0,
                                  child: CircularProgressIndicator(
                                    strokeWidth: 2.0,
                                    valueColor: AlwaysStoppedAnimation<Color>(
                                        Colors.white),
                                  ),
                                ),
                              ],
                            ),
                    ),
                  ),
                ),
              ),
            ],
          );
        },
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'There are no bottons to push :)',
            ),
            Text(
              'Just turn off your internet.',
            ),
          ],
        ),
      ),
    );
  }
}

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DemoPage(),
    );
  }
}