1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Image_unittest.cpp : Unittets of the Image and ImageSibling classes.
8
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
11
12 #include "libANGLE/Image.h"
13 #include "libANGLE/Renderbuffer.h"
14 #include "libANGLE/Texture.h"
15 #include "libANGLE/renderer/ImageImpl_mock.h"
16 #include "libANGLE/renderer/RenderbufferImpl_mock.h"
17 #include "libANGLE/renderer/TextureImpl_mock.h"
18 #include "tests/angle_unittests_utils.h"
19
20 using ::testing::_;
21 using ::testing::NiceMock;
22 using ::testing::Return;
23
24 namespace angle
25 {
ACTION(CreateMockImageImpl)26 ACTION(CreateMockImageImpl)
27 {
28 return new rx::MockImageImpl(arg0);
29 }
30
31 // Verify ref counts are maintained between images and their siblings when objects are deleted
TEST(ImageTest,RefCounting)32 TEST(ImageTest, RefCounting)
33 {
34 NiceMock<rx::MockGLFactory> mockGLFactory;
35 NiceMock<rx::MockEGLFactory> mockEGLFactory;
36
37 // Create a texture and an EGL image that uses the texture as its source
38 rx::MockTextureImpl *textureImpl = new rx::MockTextureImpl();
39 EXPECT_CALL(mockGLFactory, createTexture(_)).WillOnce(Return(textureImpl));
40 gl::Texture *texture = new gl::Texture(&mockGLFactory, {1}, gl::TextureType::_2D);
41 texture->addRef();
42
43 EXPECT_CALL(mockEGLFactory, createImage(_, _, _, _))
44 .WillOnce(CreateMockImageImpl())
45 .RetiresOnSaturation();
46
47 egl::Image *image = new egl::Image(&mockEGLFactory, {1}, nullptr, EGL_GL_TEXTURE_2D, texture,
48 egl::AttributeMap());
49 rx::MockImageImpl *imageImpl = static_cast<rx::MockImageImpl *>(image->getImplementation());
50 image->addRef();
51
52 // Verify that the image does not add a ref to its source so that the source may still be
53 // deleted
54 EXPECT_EQ(1u, texture->getRefCount());
55 EXPECT_EQ(1u, image->getRefCount());
56
57 // Create a renderbuffer and set it as a target of the EGL image
58 rx::MockRenderbufferImpl *renderbufferImpl = new rx::MockRenderbufferImpl();
59 EXPECT_CALL(mockGLFactory, createRenderbuffer(_)).WillOnce(Return(renderbufferImpl));
60 gl::Renderbuffer *renderbuffer = new gl::Renderbuffer(&mockGLFactory, {1});
61 renderbuffer->addRef();
62
63 EXPECT_CALL(*renderbufferImpl, setStorageEGLImageTarget(_, _))
64 .WillOnce(Return(angle::Result::Continue))
65 .RetiresOnSaturation();
66 EXPECT_EQ(angle::Result::Continue, renderbuffer->setStorageEGLImageTarget(nullptr, image));
67
68 // Verify that the renderbuffer added a ref to the image and the image did not add a ref to
69 // the renderbuffer
70 EXPECT_EQ(1u, texture->getRefCount());
71 EXPECT_EQ(2u, image->getRefCount());
72 EXPECT_EQ(1u, renderbuffer->getRefCount());
73
74 // Simulate deletion of the texture and verify that it is deleted but the image still exists
75 EXPECT_CALL(*imageImpl, orphan(_, _))
76 .WillOnce(Return(angle::Result::Continue))
77 .RetiresOnSaturation();
78 EXPECT_CALL(*textureImpl, destructor()).Times(1).RetiresOnSaturation();
79 texture->release(nullptr);
80 EXPECT_EQ(2u, image->getRefCount());
81 EXPECT_EQ(1u, renderbuffer->getRefCount());
82
83 // Simulate deletion of the image and verify that it still exists because the renderbuffer holds
84 // a ref
85 image->release(nullptr);
86 EXPECT_EQ(1u, image->getRefCount());
87 EXPECT_EQ(1u, renderbuffer->getRefCount());
88
89 // Simulate deletion of the renderbuffer and verify that the deletion cascades to all objects
90 EXPECT_CALL(*imageImpl, destructor()).Times(1).RetiresOnSaturation();
91 EXPECT_CALL(*imageImpl, orphan(_, _))
92 .WillOnce(Return(angle::Result::Continue))
93 .RetiresOnSaturation();
94
95 EXPECT_CALL(*renderbufferImpl, destructor()).Times(1).RetiresOnSaturation();
96
97 renderbuffer->release(nullptr);
98 }
99
100 // Verify that respecifying textures releases references to the Image.
TEST(ImageTest,RespecificationReleasesReferences)101 TEST(ImageTest, RespecificationReleasesReferences)
102 {
103 NiceMock<rx::MockGLFactory> mockGLFactory;
104 NiceMock<rx::MockEGLFactory> mockEGLFactory;
105
106 // Create a texture and an EGL image that uses the texture as its source
107 rx::MockTextureImpl *textureImpl = new rx::MockTextureImpl();
108 EXPECT_CALL(mockGLFactory, createTexture(_)).WillOnce(Return(textureImpl));
109 gl::Texture *texture = new gl::Texture(&mockGLFactory, {1}, gl::TextureType::_2D);
110 texture->addRef();
111
112 gl::PixelUnpackState defaultUnpackState;
113
114 EXPECT_CALL(*textureImpl, setImage(_, _, _, _, _, _, _, _, _))
115 .WillOnce(Return(angle::Result::Continue))
116 .RetiresOnSaturation();
117 EXPECT_EQ(
118 angle::Result::Continue,
119 texture->setImage(nullptr, defaultUnpackState, nullptr, gl::TextureTarget::_2D, 0, GL_RGBA8,
120 gl::Extents(1, 1, 1), GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
121
122 EXPECT_CALL(mockEGLFactory, createImage(_, _, _, _))
123 .WillOnce(CreateMockImageImpl())
124 .RetiresOnSaturation();
125
126 egl::Image *image = new egl::Image(&mockEGLFactory, {1}, nullptr, EGL_GL_TEXTURE_2D, texture,
127 egl::AttributeMap());
128 image->addRef();
129
130 // Verify that the image did not add a ref to it's source.
131 EXPECT_EQ(1u, texture->getRefCount());
132 EXPECT_EQ(1u, image->getRefCount());
133
134 // Respecify the texture and verify that the image is orphaned
135 rx::MockImageImpl *imageImpl = static_cast<rx::MockImageImpl *>(image->getImplementation());
136 EXPECT_CALL(*imageImpl, orphan(_, _))
137 .WillOnce(Return(angle::Result::Continue))
138 .RetiresOnSaturation();
139 EXPECT_CALL(*textureImpl, setImage(_, _, _, _, _, _, _, _, _))
140 .WillOnce(Return(angle::Result::Continue))
141 .RetiresOnSaturation();
142
143 EXPECT_EQ(
144 angle::Result::Continue,
145 texture->setImage(nullptr, defaultUnpackState, nullptr, gl::TextureTarget::_2D, 0, GL_RGBA8,
146 gl::Extents(1, 1, 1), GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
147
148 EXPECT_EQ(1u, texture->getRefCount());
149 EXPECT_EQ(1u, image->getRefCount());
150
151 // Delete the texture and verify that the image still exists
152 EXPECT_CALL(*textureImpl, destructor()).Times(1).RetiresOnSaturation();
153 texture->release(nullptr);
154
155 EXPECT_EQ(1u, image->getRefCount());
156
157 // Delete the image
158 EXPECT_CALL(*imageImpl, destructor()).Times(1).RetiresOnSaturation();
159 image->release(nullptr);
160 }
161 } // namespace angle
162