1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gpu/command_buffer/service/texture_definition.h"
9 #include "base/memory/linked_ptr.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/synchronization/lock.h"
12 #include "gpu/command_buffer/service/texture_manager.h"
13 #include "ui/gl/gl_image.h"
14 #include "ui/gl/gl_implementation.h"
15 #include "ui/gl/scoped_binders.h"
17 #if !defined(OS_MACOSX)
18 #include "ui/gl/gl_surface_egl.h"
26 class GLImageSync
: public gfx::GLImage
{
28 explicit GLImageSync(const scoped_refptr
<NativeImageBuffer
>& buffer
,
29 const gfx::Size
& size
);
32 void Destroy(bool have_context
) override
;
33 gfx::Size
GetSize() override
;
34 bool BindTexImage(unsigned target
) override
;
35 void ReleaseTexImage(unsigned target
) override
;
36 bool CopyTexImage(unsigned target
) override
;
37 void WillUseTexImage() override
;
38 void WillModifyTexImage() override
;
39 void DidModifyTexImage() override
;
40 void DidUseTexImage() override
;
41 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget
,
43 gfx::OverlayTransform transform
,
44 const gfx::Rect
& bounds_rect
,
45 const gfx::RectF
& crop_rect
) override
;
48 ~GLImageSync() override
;
51 scoped_refptr
<NativeImageBuffer
> buffer_
;
54 DISALLOW_COPY_AND_ASSIGN(GLImageSync
);
57 GLImageSync::GLImageSync(const scoped_refptr
<NativeImageBuffer
>& buffer
,
58 const gfx::Size
& size
)
59 : buffer_(buffer
), size_(size
) {
61 buffer
->AddClient(this);
64 GLImageSync::~GLImageSync() {
66 buffer_
->RemoveClient(this);
69 void GLImageSync::Destroy(bool have_context
) {
72 gfx::Size
GLImageSync::GetSize() {
76 bool GLImageSync::BindTexImage(unsigned target
) {
81 void GLImageSync::ReleaseTexImage(unsigned target
) {
85 bool GLImageSync::CopyTexImage(unsigned target
) {
89 void GLImageSync::WillUseTexImage() {
92 void GLImageSync::DidUseTexImage() {
95 void GLImageSync::WillModifyTexImage() {
98 void GLImageSync::DidModifyTexImage() {
101 bool GLImageSync::ScheduleOverlayPlane(gfx::AcceleratedWidget widget
,
103 gfx::OverlayTransform transform
,
104 const gfx::Rect
& bounds_rect
,
105 const gfx::RectF
& crop_rect
) {
110 #if !defined(OS_MACOSX)
111 class NativeImageBufferEGL
: public NativeImageBuffer
{
113 static scoped_refptr
<NativeImageBufferEGL
> Create(GLuint texture_id
);
116 NativeImageBufferEGL(EGLDisplay display
, EGLImageKHR image
);
117 ~NativeImageBufferEGL() override
;
118 void AddClient(gfx::GLImage
* client
) override
;
119 void RemoveClient(gfx::GLImage
* client
) override
;
120 bool IsClient(gfx::GLImage
* client
) override
;
121 void BindToTexture(GLenum target
) override
;
123 EGLDisplay egl_display_
;
124 EGLImageKHR egl_image_
;
129 ClientInfo(gfx::GLImage
* client
);
132 gfx::GLImage
* client
;
133 bool needs_wait_before_read
;
135 std::list
<ClientInfo
> client_infos_
;
136 gfx::GLImage
* write_client_
;
138 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL
);
141 scoped_refptr
<NativeImageBufferEGL
> NativeImageBufferEGL::Create(
143 EGLDisplay egl_display
= gfx::GLSurfaceEGL::GetHardwareDisplay();
144 EGLContext egl_context
= eglGetCurrentContext();
146 DCHECK_NE(EGL_NO_CONTEXT
, egl_context
);
147 DCHECK_NE(EGL_NO_DISPLAY
, egl_display
);
148 DCHECK(glIsTexture(texture_id
));
150 DCHECK(gfx::g_driver_egl
.ext
.b_EGL_KHR_image_base
&&
151 gfx::g_driver_egl
.ext
.b_EGL_KHR_gl_texture_2D_image
&&
152 gfx::g_driver_gl
.ext
.b_GL_OES_EGL_image
);
154 const EGLint egl_attrib_list
[] = {
155 EGL_GL_TEXTURE_LEVEL_KHR
, 0, EGL_IMAGE_PRESERVED_KHR
, EGL_TRUE
, EGL_NONE
};
156 EGLClientBuffer egl_buffer
= reinterpret_cast<EGLClientBuffer
>(texture_id
);
157 EGLenum egl_target
= EGL_GL_TEXTURE_2D_KHR
; // TODO
159 EGLImageKHR egl_image
= eglCreateImageKHR(
160 egl_display
, egl_context
, egl_target
, egl_buffer
, egl_attrib_list
);
162 if (egl_image
== EGL_NO_IMAGE_KHR
)
165 return new NativeImageBufferEGL(egl_display
, egl_image
);
168 NativeImageBufferEGL::ClientInfo::ClientInfo(gfx::GLImage
* client
)
169 : client(client
), needs_wait_before_read(true) {}
171 NativeImageBufferEGL::ClientInfo::~ClientInfo() {}
173 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display
,
175 : NativeImageBuffer(),
176 egl_display_(display
),
178 write_client_(NULL
) {
179 DCHECK(egl_display_
!= EGL_NO_DISPLAY
);
180 DCHECK(egl_image_
!= EGL_NO_IMAGE_KHR
);
183 NativeImageBufferEGL::~NativeImageBufferEGL() {
184 DCHECK(client_infos_
.empty());
185 if (egl_image_
!= EGL_NO_IMAGE_KHR
)
186 eglDestroyImageKHR(egl_display_
, egl_image_
);
189 void NativeImageBufferEGL::AddClient(gfx::GLImage
* client
) {
190 base::AutoLock
lock(lock_
);
191 client_infos_
.push_back(ClientInfo(client
));
194 void NativeImageBufferEGL::RemoveClient(gfx::GLImage
* client
) {
195 base::AutoLock
lock(lock_
);
196 if (write_client_
== client
)
197 write_client_
= NULL
;
198 for (std::list
<ClientInfo
>::iterator it
= client_infos_
.begin();
199 it
!= client_infos_
.end();
201 if (it
->client
== client
) {
202 client_infos_
.erase(it
);
209 bool NativeImageBufferEGL::IsClient(gfx::GLImage
* client
) {
210 base::AutoLock
lock(lock_
);
211 for (std::list
<ClientInfo
>::iterator it
= client_infos_
.begin();
212 it
!= client_infos_
.end();
214 if (it
->client
== client
)
220 void NativeImageBufferEGL::BindToTexture(GLenum target
) {
221 DCHECK(egl_image_
!= EGL_NO_IMAGE_KHR
);
222 glEGLImageTargetTexture2DOES(target
, egl_image_
);
223 DCHECK_EQ(static_cast<EGLint
>(EGL_SUCCESS
), eglGetError());
224 DCHECK_EQ(static_cast<GLenum
>(GL_NO_ERROR
), glGetError());
229 class NativeImageBufferStub
: public NativeImageBuffer
{
231 NativeImageBufferStub() : NativeImageBuffer() {}
234 ~NativeImageBufferStub() override
{}
235 void AddClient(gfx::GLImage
* client
) override
{}
236 void RemoveClient(gfx::GLImage
* client
) override
{}
237 bool IsClient(gfx::GLImage
* client
) override
{ return true; }
238 void BindToTexture(GLenum target
) override
{}
240 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub
);
243 } // anonymous namespace
246 scoped_refptr
<NativeImageBuffer
> NativeImageBuffer::Create(GLuint texture_id
) {
247 switch (gfx::GetGLImplementation()) {
248 #if !defined(OS_MACOSX)
249 case gfx::kGLImplementationEGLGLES2
:
250 return NativeImageBufferEGL::Create(texture_id
);
252 case gfx::kGLImplementationMockGL
:
253 return new NativeImageBufferStub
;
260 TextureDefinition::LevelInfo::LevelInfo(GLenum target
,
261 GLenum internal_format
,
270 internal_format(internal_format
),
279 TextureDefinition::LevelInfo::~LevelInfo() {}
281 TextureDefinition::TextureDefinition()
292 TextureDefinition::TextureDefinition(
294 unsigned int version
,
295 const scoped_refptr
<NativeImageBuffer
>& image_buffer
)
297 target_(texture
->target()),
298 image_buffer_(image_buffer
.get()
300 : NativeImageBuffer::Create(texture
->service_id())),
301 min_filter_(texture
->min_filter()),
302 mag_filter_(texture
->mag_filter()),
303 wrap_s_(texture
->wrap_s()),
304 wrap_t_(texture
->wrap_t()),
305 usage_(texture
->usage()),
306 immutable_(texture
->IsImmutable()) {
308 DCHECK(!texture
->face_infos_
.empty());
309 DCHECK(!texture
->face_infos_
[0].level_infos
.empty());
310 DCHECK(!texture
->NeedsMips());
311 DCHECK(texture
->face_infos_
[0].level_infos
[0].width
);
312 DCHECK(texture
->face_infos_
[0].level_infos
[0].height
);
314 const Texture::FaceInfo
& first_face
= texture
->face_infos_
[0];
315 scoped_refptr
<gfx::GLImage
> gl_image(
316 new GLImageSync(image_buffer_
,
317 gfx::Size(first_face
.level_infos
[0].width
,
318 first_face
.level_infos
[0].height
)));
319 texture
->SetLevelImage(NULL
, target_
, 0, gl_image
.get());
322 level_infos_
.clear();
323 const Texture::LevelInfo
& level
= first_face
.level_infos
[0];
324 LevelInfo
info(level
.target
,
325 level
.internal_format
,
333 std::vector
<LevelInfo
> infos
;
334 infos
.push_back(info
);
335 level_infos_
.push_back(infos
);
338 TextureDefinition::~TextureDefinition() {
341 Texture
* TextureDefinition::CreateTexture() const {
342 if (!image_buffer_
.get())
346 glGenTextures(1, &texture_id
);
348 Texture
* texture(new Texture(texture_id
));
349 UpdateTexture(texture
);
354 void TextureDefinition::UpdateTexture(Texture
* texture
) const {
355 gfx::ScopedTextureBinder
texture_binder(target_
, texture
->service_id());
356 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, min_filter_
);
357 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, mag_filter_
);
358 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, wrap_s_
);
359 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, wrap_t_
);
360 if (image_buffer_
.get())
361 image_buffer_
->BindToTexture(target_
);
362 // We have to make sure the changes are visible to other clients in this share
363 // group. As far as the clients are concerned, the mailbox semantics only
364 // demand a single flush from the client after changes are first made,
365 // and it is not visible to them when another share group boundary is crossed.
366 // We could probably track this and be a bit smarter about when to flush
370 texture
->face_infos_
.resize(1);
371 for (size_t i
= 0; i
< level_infos_
.size(); i
++) {
372 const LevelInfo
& base_info
= level_infos_
[i
][0];
373 const size_t levels_needed
= TextureManager::ComputeMipMapCount(
374 base_info
.target
, base_info
.width
, base_info
.height
, base_info
.depth
);
375 DCHECK(level_infos_
.size() <= levels_needed
);
376 texture
->face_infos_
[0].level_infos
.resize(levels_needed
);
377 for (size_t n
= 0; n
< level_infos_
.size(); n
++) {
378 const LevelInfo
& info
= level_infos_
[i
][n
];
379 texture
->SetLevelInfo(NULL
,
382 info
.internal_format
,
392 if (image_buffer_
.get()) {
393 texture
->SetLevelImage(
399 gfx::Size(level_infos_
[0][0].width
, level_infos_
[0][0].height
)));
402 texture
->target_
= target_
;
403 texture
->SetImmutable(immutable_
);
404 texture
->min_filter_
= min_filter_
;
405 texture
->mag_filter_
= mag_filter_
;
406 texture
->wrap_s_
= wrap_s_
;
407 texture
->wrap_t_
= wrap_t_
;
408 texture
->usage_
= usage_
;
411 bool TextureDefinition::Matches(const Texture
* texture
) const {
412 DCHECK(target_
== texture
->target());
413 if (texture
->min_filter_
!= min_filter_
||
414 texture
->mag_filter_
!= mag_filter_
||
415 texture
->wrap_s_
!= wrap_s_
||
416 texture
->wrap_t_
!= wrap_t_
||
417 texture
->SafeToRenderFrom() != SafeToRenderFrom()) {
421 // All structural changes should have orphaned the texture.
422 if (image_buffer_
.get() && !texture
->GetLevelImage(texture
->target(), 0))
428 bool TextureDefinition::SafeToRenderFrom() const {
429 for (const std::vector
<LevelInfo
>& face_info
: level_infos_
) {
430 for (const LevelInfo
& level_info
: face_info
) {
431 if (!level_info
.cleared
) {