|
|
|
@ -328,6 +328,28 @@ void AttachTexture(GLuint fbo, GLenum attachment, const ImageView* image_view) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[[nodiscard]] GLenum ShaderFormat(Shader::ImageFormat format) { |
|
|
|
switch (format) { |
|
|
|
case Shader::ImageFormat::Typeless: |
|
|
|
break; |
|
|
|
case Shader::ImageFormat::R8_SINT: |
|
|
|
return GL_R8I; |
|
|
|
case Shader::ImageFormat::R8_UINT: |
|
|
|
return GL_R8UI; |
|
|
|
case Shader::ImageFormat::R16_UINT: |
|
|
|
return GL_R16UI; |
|
|
|
case Shader::ImageFormat::R16_SINT: |
|
|
|
return GL_R16I; |
|
|
|
case Shader::ImageFormat::R32_UINT: |
|
|
|
return GL_R32UI; |
|
|
|
case Shader::ImageFormat::R32G32_UINT: |
|
|
|
return GL_RG32UI; |
|
|
|
case Shader::ImageFormat::R32G32B32A32_UINT: |
|
|
|
return GL_RGBA32UI; |
|
|
|
} |
|
|
|
UNREACHABLE_MSG("Invalid image format={}", format); |
|
|
|
return GL_R32UI; |
|
|
|
} |
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
ImageBufferMap::~ImageBufferMap() { |
|
|
|
@ -837,21 +859,28 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI |
|
|
|
} else { |
|
|
|
internal_format = MaxwellToGL::GetFormatTuple(format).internal_format; |
|
|
|
} |
|
|
|
VideoCommon::SubresourceRange flatten_range = info.range; |
|
|
|
std::array<GLuint, 2> handles; |
|
|
|
stored_views.reserve(2); |
|
|
|
|
|
|
|
full_range = info.range; |
|
|
|
flat_range = info.range; |
|
|
|
set_object_label = device.HasDebuggingToolAttached(); |
|
|
|
is_render_target = info.IsRenderTarget(); |
|
|
|
original_texture = image.texture.handle; |
|
|
|
num_samples = image.info.num_samples; |
|
|
|
if (!is_render_target) { |
|
|
|
swizzle[0] = info.x_source; |
|
|
|
swizzle[1] = info.y_source; |
|
|
|
swizzle[2] = info.z_source; |
|
|
|
swizzle[3] = info.w_source; |
|
|
|
} |
|
|
|
switch (info.type) { |
|
|
|
case ImageViewType::e1DArray: |
|
|
|
flatten_range.extent.layers = 1; |
|
|
|
flat_range.extent.layers = 1; |
|
|
|
[[fallthrough]]; |
|
|
|
case ImageViewType::e1D: |
|
|
|
glGenTextures(2, handles.data()); |
|
|
|
SetupView(device, image, Shader::TextureType::Color1D, handles[0], info, flatten_range); |
|
|
|
SetupView(device, image, Shader::TextureType::ColorArray1D, handles[1], info, info.range); |
|
|
|
SetupView(Shader::TextureType::Color1D); |
|
|
|
SetupView(Shader::TextureType::ColorArray1D); |
|
|
|
break; |
|
|
|
case ImageViewType::e2DArray: |
|
|
|
flatten_range.extent.layers = 1; |
|
|
|
flat_range.extent.layers = 1; |
|
|
|
[[fallthrough]]; |
|
|
|
case ImageViewType::e2D: |
|
|
|
if (True(flags & VideoCommon::ImageViewFlagBits::Slice)) { |
|
|
|
@ -861,26 +890,23 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI |
|
|
|
.base = {.level = info.range.base.level, .layer = 0}, |
|
|
|
.extent = {.levels = 1, .layers = 1}, |
|
|
|
}; |
|
|
|
glGenTextures(1, handles.data()); |
|
|
|
SetupView(device, image, Shader::TextureType::Color3D, handles[0], info, slice_range); |
|
|
|
full_range = slice_range; |
|
|
|
|
|
|
|
SetupView(Shader::TextureType::Color3D); |
|
|
|
} else { |
|
|
|
glGenTextures(2, handles.data()); |
|
|
|
SetupView(device, image, Shader::TextureType::Color2D, handles[0], info, flatten_range); |
|
|
|
SetupView(device, image, Shader::TextureType::ColorArray2D, handles[1], info, |
|
|
|
info.range); |
|
|
|
SetupView(Shader::TextureType::Color2D); |
|
|
|
SetupView(Shader::TextureType::ColorArray2D); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ImageViewType::e3D: |
|
|
|
glGenTextures(1, handles.data()); |
|
|
|
SetupView(device, image, Shader::TextureType::Color3D, handles[0], info, info.range); |
|
|
|
SetupView(Shader::TextureType::Color3D); |
|
|
|
break; |
|
|
|
case ImageViewType::CubeArray: |
|
|
|
flatten_range.extent.layers = 6; |
|
|
|
flat_range.extent.layers = 6; |
|
|
|
[[fallthrough]]; |
|
|
|
case ImageViewType::Cube: |
|
|
|
glGenTextures(2, handles.data()); |
|
|
|
SetupView(device, image, Shader::TextureType::ColorCube, handles[0], info, flatten_range); |
|
|
|
SetupView(device, image, Shader::TextureType::ColorArrayCube, handles[1], info, info.range); |
|
|
|
SetupView(Shader::TextureType::ColorCube); |
|
|
|
SetupView(Shader::TextureType::ColorArrayCube); |
|
|
|
break; |
|
|
|
case ImageViewType::Rect: |
|
|
|
UNIMPLEMENTED(); |
|
|
|
@ -928,22 +954,62 @@ ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, |
|
|
|
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageParams& params) |
|
|
|
: VideoCommon::ImageViewBase{params}, views{runtime.null_image_views} {} |
|
|
|
|
|
|
|
void ImageView::SetupView(const Device& device, Image& image, Shader::TextureType view_type, |
|
|
|
GLuint handle, const VideoCommon::ImageViewInfo& info, |
|
|
|
VideoCommon::SubresourceRange view_range) { |
|
|
|
const GLuint parent = image.texture.handle; |
|
|
|
const GLenum target = ImageTarget(view_type, image.info.num_samples); |
|
|
|
glTextureView(handle, target, parent, internal_format, view_range.base.level, |
|
|
|
GLuint ImageView::StorageView(Shader::TextureType texture_type, Shader::ImageFormat image_format) { |
|
|
|
if (image_format == Shader::ImageFormat::Typeless) { |
|
|
|
return Handle(texture_type); |
|
|
|
} |
|
|
|
const bool is_signed{image_format == Shader::ImageFormat::R8_SINT || |
|
|
|
image_format == Shader::ImageFormat::R16_SINT}; |
|
|
|
if (!storage_views) { |
|
|
|
storage_views = std::make_unique<StorageViews>(); |
|
|
|
} |
|
|
|
auto& type_views{is_signed ? storage_views->signeds : storage_views->unsigneds}; |
|
|
|
GLuint& view{type_views[static_cast<size_t>(texture_type)]}; |
|
|
|
if (view == 0) { |
|
|
|
view = MakeView(texture_type, ShaderFormat(image_format)); |
|
|
|
} |
|
|
|
return view; |
|
|
|
} |
|
|
|
|
|
|
|
void ImageView::SetupView(Shader::TextureType view_type) { |
|
|
|
views[static_cast<size_t>(view_type)] = MakeView(view_type, internal_format); |
|
|
|
} |
|
|
|
|
|
|
|
GLuint ImageView::MakeView(Shader::TextureType view_type, GLenum view_format) { |
|
|
|
VideoCommon::SubresourceRange view_range; |
|
|
|
switch (view_type) { |
|
|
|
case Shader::TextureType::Color1D: |
|
|
|
case Shader::TextureType::Color2D: |
|
|
|
case Shader::TextureType::ColorCube: |
|
|
|
view_range = flat_range; |
|
|
|
break; |
|
|
|
case Shader::TextureType::ColorArray1D: |
|
|
|
case Shader::TextureType::ColorArray2D: |
|
|
|
case Shader::TextureType::Color3D: |
|
|
|
case Shader::TextureType::ColorArrayCube: |
|
|
|
view_range = full_range; |
|
|
|
break; |
|
|
|
default: |
|
|
|
UNREACHABLE(); |
|
|
|
} |
|
|
|
OGLTextureView& view = stored_views.emplace_back(); |
|
|
|
view.Create(); |
|
|
|
|
|
|
|
const GLenum target = ImageTarget(view_type, num_samples); |
|
|
|
glTextureView(view.handle, target, original_texture, view_format, view_range.base.level, |
|
|
|
view_range.extent.levels, view_range.base.layer, view_range.extent.layers); |
|
|
|
if (!info.IsRenderTarget()) { |
|
|
|
ApplySwizzle(handle, format, info.Swizzle()); |
|
|
|
if (!is_render_target) { |
|
|
|
std::array<SwizzleSource, 4> casted_swizzle; |
|
|
|
std::ranges::transform(swizzle, casted_swizzle.begin(), [](u8 component_swizzle) { |
|
|
|
return static_cast<SwizzleSource>(component_swizzle); |
|
|
|
}); |
|
|
|
ApplySwizzle(view.handle, format, casted_swizzle); |
|
|
|
} |
|
|
|
if (device.HasDebuggingToolAttached()) { |
|
|
|
if (set_object_label) { |
|
|
|
const std::string name = VideoCommon::Name(*this); |
|
|
|
glObjectLabel(GL_TEXTURE, handle, static_cast<GLsizei>(name.size()), name.data()); |
|
|
|
glObjectLabel(GL_TEXTURE, view.handle, static_cast<GLsizei>(name.size()), name.data()); |
|
|
|
} |
|
|
|
stored_views.emplace_back().handle = handle; |
|
|
|
views[static_cast<size_t>(view_type)] = handle; |
|
|
|
return view.handle; |
|
|
|
} |
|
|
|
|
|
|
|
Sampler::Sampler(TextureCacheRuntime& runtime, const TSCEntry& config) { |
|
|
|
|