summaryrefslogtreecommitdiff
path: root/chromium/components/viz/common/gpu/texture_allocation.cc
blob: 90b51e28e6a8ebe746554dd78c3cc3d79a4ceb52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/viz/common/gpu/texture_allocation.h"

#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/raster_interface.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"

namespace viz {

// static
TextureAllocation TextureAllocation::MakeTextureId(
    gpu::gles2::GLES2Interface* gl,
    const gpu::Capabilities& caps,
    ResourceFormat format,
    bool use_gpu_memory_buffer_resources,
    bool for_framebuffer_attachment) {
  uint32_t texture_target = GL_TEXTURE_2D;

  bool overlay_candidate = use_gpu_memory_buffer_resources &&
                           caps.texture_storage_image &&
                           IsGpuMemoryBufferFormatSupported(format);
  if (overlay_candidate) {
    texture_target = gpu::GetBufferTextureTarget(gfx::BufferUsage::SCANOUT,
                                                 BufferFormat(format), caps);
  }

  uint32_t texture_id;
  gl->GenTextures(1, &texture_id);
  gl->BindTexture(texture_target, texture_id);
  gl->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  gl->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

  if (for_framebuffer_attachment && caps.texture_usage) {
    // Set GL_FRAMEBUFFER_ATTACHMENT_ANGLE since we'll be binding these
    // textures as a framebuffer for drawing directly to them on the gpu.
    gl->TexParameteri(texture_target, GL_TEXTURE_USAGE_ANGLE,
                      GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
  }
  gl->BindTexture(texture_target, 0);
  return {texture_id, texture_target, overlay_candidate};
}

// static
void TextureAllocation::AllocateStorage(gpu::gles2::GLES2Interface* gl,
                                        const gpu::Capabilities& caps,
                                        ResourceFormat format,
                                        const gfx::Size& size,
                                        const TextureAllocation& alloc,
                                        const gfx::ColorSpace& color_space) {
  gl->BindTexture(alloc.texture_target, alloc.texture_id);
  // Allocate backing storage for the texture. The best choice is to use
  // GpuMemoryBuffers if we can use the texture as an overlay and its asked
  // for by the caller. Else we try to make the texture have immutable
  // storage, and finally fall back to standard storage if we must.
  if (alloc.overlay_candidate) {
    // |overlay_candidate| was only set when these were true, and
    // |use_gpu_memory_buffer_resources| was specified by the caller.
    DCHECK(caps.texture_storage_image);
    DCHECK(IsGpuMemoryBufferFormatSupported(format));

    gl->TexStorage2DImageCHROMIUM(
        alloc.texture_target, TextureStorageFormat(format), GL_SCANOUT_CHROMIUM,
        size.width(), size.height());
    if (color_space.IsValid()) {
      gl->SetColorSpaceMetadataCHROMIUM(
          alloc.texture_id, reinterpret_cast<GLColorSpace>(
                                const_cast<gfx::ColorSpace*>(&color_space)));
    }
  } else if (caps.texture_storage) {
    gl->TexStorage2DEXT(alloc.texture_target, 1, TextureStorageFormat(format),
                        size.width(), size.height());
  } else {
    gl->TexImage2D(alloc.texture_target, 0, GLInternalFormat(format),
                   size.width(), size.height(), 0, GLDataFormat(format),
                   GLDataType(format), nullptr);
  }
}

// static
void TextureAllocation::AllocateStorage(gpu::raster::RasterInterface* ri,
                                        const gpu::Capabilities& caps,
                                        ResourceFormat format,
                                        const gfx::Size& size,
                                        const TextureAllocation& alloc,
                                        const gfx::ColorSpace& color_space) {
  // ETC1 resources cannot be preallocated.
  if (format == ETC1)
    return;
  ri->TexStorage2D(alloc.texture_id, 1, size.width(), size.height());
  if (alloc.overlay_candidate && color_space.IsValid()) {
    ri->SetColorSpaceMetadata(alloc.texture_id,
                              reinterpret_cast<GLColorSpace>(
                                  const_cast<gfx::ColorSpace*>(&color_space)));
  }
}

void TextureAllocation::UploadStorage(gpu::gles2::GLES2Interface* gl,
                                      const gpu::Capabilities& caps,
                                      ResourceFormat format,
                                      const gfx::Size& size,
                                      const TextureAllocation& alloc,
                                      const gfx::ColorSpace& color_space,
                                      const void* pixels) {
  if (format == ETC1) {
    DCHECK_EQ(alloc.texture_target, static_cast<GLenum>(GL_TEXTURE_2D));
    int num_bytes = ResourceSizes::CheckedSizeInBytes<int>(size, ETC1);

    gl->BindTexture(alloc.texture_target, alloc.texture_id);
    gl->CompressedTexImage2D(alloc.texture_target, 0, GLInternalFormat(ETC1),
                             size.width(), size.height(), 0, num_bytes,
                             const_cast<void*>(pixels));
  } else {
    AllocateStorage(gl, caps, format, size, alloc, color_space);
    gl->TexSubImage2D(alloc.texture_target, 0, 0, 0, size.width(),
                      size.height(), GLDataFormat(format), GLDataType(format),
                      const_cast<void*>(pixels));
  }
}

}  // namespace viz