Commit 21045f5a by Jamie Madill

Revert "Fix ResourceManager create-on-bind reallocations."

Build break on GPU FYI Bots on Linux/Mac: http://build.chromium.org/p/chromium.gpu.fyi/builders/GPU%20Mac%20Builder/builds/28092 This reverts commit 61ce1a41. Change-Id: If2e7fb35c769708a783a32932b777dc97eaba8a4 Reviewed-on: https://chromium-review.googlesource.com/261590Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 47fd36a7
...@@ -9,29 +9,13 @@ ...@@ -9,29 +9,13 @@
#include "libANGLE/HandleAllocator.h" #include "libANGLE/HandleAllocator.h"
#include <algorithm>
#include "common/debug.h" #include "common/debug.h"
namespace gl namespace gl
{ {
struct HandleAllocator::HandleRangeComparator
{
bool operator()(const HandleRange &range, GLuint handle) const
{
return (handle < range.begin);
}
};
HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1) HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1)
{ {
mUnallocatedList.push_back(HandleRange(1, std::numeric_limits<GLuint>::max() - 1));
}
HandleAllocator::HandleAllocator(GLuint maximumHandleValue) : mBaseValue(1), mNextValue(1)
{
mUnallocatedList.push_back(HandleRange(1, maximumHandleValue));
} }
HandleAllocator::~HandleAllocator() HandleAllocator::~HandleAllocator()
...@@ -47,86 +31,32 @@ void HandleAllocator::setBaseHandle(GLuint value) ...@@ -47,86 +31,32 @@ void HandleAllocator::setBaseHandle(GLuint value)
GLuint HandleAllocator::allocate() GLuint HandleAllocator::allocate()
{ {
ASSERT(!mUnallocatedList.empty() || !mReleasedList.empty()); if (mFreeValues.size())
// Allocate from released list, constant time.
if (!mReleasedList.empty())
{
GLuint reusedHandle = mReleasedList.back();
mReleasedList.pop_back();
return reusedHandle;
}
// Allocate from unallocated list, constant time.
auto listIt = mUnallocatedList.begin();
GLuint freeListHandle = listIt->begin;
ASSERT(freeListHandle > 0);
listIt->begin++;
if (listIt->begin == listIt->end)
{ {
mUnallocatedList.erase(listIt); GLuint handle = mFreeValues.back();
mFreeValues.pop_back();
return handle;
} }
return mNextValue++;
return freeListHandle;
} }
void HandleAllocator::release(GLuint handle) void HandleAllocator::release(GLuint handle)
{ {
// Add to released list, constant time. if (handle == mNextValue - 1)
mReleasedList.push_back(handle);
}
void HandleAllocator::reserve(GLuint handle)
{
// Clear from released list -- might be a slow operation.
if (!mReleasedList.empty())
{
auto releasedIt = std::find(mReleasedList.begin(), mReleasedList.end(), handle);
if (releasedIt != mReleasedList.end())
{
mReleasedList.erase(releasedIt);
return;
}
}
// Not in released list, reserve in the unallocated list.
auto boundIt = std::lower_bound(mUnallocatedList.begin(), mUnallocatedList.end(), handle, HandleRangeComparator());
ASSERT(boundIt != mUnallocatedList.end());
GLuint begin = boundIt->begin;
GLuint end = boundIt->end;
if (handle == begin || handle == end)
{ {
if (begin + 1 == end) // Don't drop below base value
if(mNextValue > mBaseValue)
{ {
mUnallocatedList.erase(boundIt); mNextValue--;
} }
else if (handle == begin)
{
boundIt->begin++;
} }
else else
{ {
ASSERT(handle == end); // Only free handles that we own - don't drop below the base value
boundIt->end--; if (handle >= mBaseValue)
}
return;
}
// need to split the range
auto placementIt = mUnallocatedList.erase(boundIt);
if (begin != handle)
{ {
placementIt = mUnallocatedList.insert(placementIt, HandleRange(begin, handle)); mFreeValues.push_back(handle);
} }
if (handle + 1 != end)
{
mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end));
} }
} }
......
...@@ -14,26 +14,21 @@ ...@@ -14,26 +14,21 @@
#include "angle_gl.h" #include "angle_gl.h"
#include <stack> #include <vector>
namespace gl namespace gl
{ {
class HandleAllocator final class HandleAllocator
{ {
public: public:
// Maximum handle = MAX_UINT-1
HandleAllocator(); HandleAllocator();
// Specify maximum handle value virtual ~HandleAllocator();
HandleAllocator(GLuint maximumHandleValue);
~HandleAllocator();
void setBaseHandle(GLuint value); void setBaseHandle(GLuint value);
GLuint allocate(); GLuint allocate();
void release(GLuint handle); void release(GLuint handle);
void reserve(GLuint handle);
private: private:
DISALLOW_COPY_AND_ASSIGN(HandleAllocator); DISALLOW_COPY_AND_ASSIGN(HandleAllocator);
...@@ -42,22 +37,6 @@ class HandleAllocator final ...@@ -42,22 +37,6 @@ class HandleAllocator final
GLuint mNextValue; GLuint mNextValue;
typedef std::vector<GLuint> HandleList; typedef std::vector<GLuint> HandleList;
HandleList mFreeValues; HandleList mFreeValues;
struct HandleRange
{
HandleRange(GLuint beginIn, GLuint endIn) : begin(beginIn), end(endIn) {}
GLuint begin;
GLuint end;
};
struct HandleRangeComparator;
// The freelist consists of never-allocated handles, stored
// as ranges, and handles that were previously allocated and
// released, stored in a stack.
std::vector<HandleRange> mUnallocatedList;
std::vector<GLuint> mReleasedList;
}; };
} }
......
//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Unit tests for HandleAllocator.
//
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "libANGLE/HandleAllocator.h"
namespace
{
TEST(HandleAllocatorTest, ReservationsWithGaps)
{
gl::HandleAllocator allocator;
std::set<GLuint> allocationList;
for (GLuint id = 2; id < 50; id += 2)
{
allocationList.insert(id);
}
for (GLuint id : allocationList)
{
allocator.reserve(id);
}
std::set<GLuint> allocatedList;
for (size_t allocationNum = 0; allocationNum < allocationList.size() * 2; ++allocationNum)
{
GLuint handle = allocator.allocate();
EXPECT_EQ(0, allocationList.count(handle));
EXPECT_EQ(0, allocatedList.count(handle));
allocatedList.insert(handle);
}
}
TEST(HandleAllocatorTest, Random)
{
gl::HandleAllocator allocator;
std::set<GLuint> allocationList;
for (size_t iterationCount = 0; iterationCount < 40; ++iterationCount)
{
for (size_t randomCount = 0; randomCount < 40; ++randomCount)
{
GLuint randomHandle = (rand() % 1000) + 1;
if (allocationList.count(randomHandle) == 0)
{
allocator.reserve(randomHandle);
allocationList.insert(randomHandle);
}
}
for (size_t normalCount = 0; normalCount < 40; ++normalCount)
{
GLuint normalHandle = allocator.allocate();
EXPECT_EQ(0, allocationList.count(normalHandle));
allocationList.insert(normalHandle);
}
}
}
TEST(HandleAllocatorTest, Reallocation)
{
// Note: no current test for overflow
gl::HandleAllocator limitedAllocator(10);
for (GLuint count = 1; count < 10; count++)
{
GLuint result = limitedAllocator.allocate();
EXPECT_EQ(count, result);
}
for (GLuint count = 1; count < 10; count++)
{
limitedAllocator.release(count);
}
for (GLuint count = 2; count < 10; count++)
{
limitedAllocator.reserve(count);
}
GLint finalResult = limitedAllocator.allocate();
EXPECT_EQ(finalResult, 1);
}
}
...@@ -27,6 +27,7 @@ Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id) ...@@ -27,6 +27,7 @@ Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id)
mInternalFormat(GL_RGBA4), mInternalFormat(GL_RGBA4),
mSamples(0) mSamples(0)
{ {
ASSERT(mRenderbuffer);
} }
Renderbuffer::~Renderbuffer() Renderbuffer::~Renderbuffer()
......
...@@ -356,84 +356,33 @@ void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer) ...@@ -356,84 +356,33 @@ void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer)
mRenderbufferMap[handle] = buffer; mRenderbufferMap[handle] = buffer;
} }
void ResourceManager::checkBufferAllocation(GLuint handle) void ResourceManager::checkBufferAllocation(unsigned int buffer)
{ {
if (handle != 0) if (buffer != 0 && !getBuffer(buffer))
{ {
auto bufferMapIt = mBufferMap.find(handle); Buffer *bufferObject = new Buffer(mFactory->createBuffer(), buffer);
bool handleAllocated = (bufferMapIt != mBufferMap.end()); mBufferMap[buffer] = bufferObject;
bufferObject->addRef();
if (handleAllocated && bufferMapIt->second != nullptr)
{
return;
}
Buffer *buffer = new Buffer(mFactory->createBuffer(), handle);
buffer->addRef();
if (handleAllocated)
{
bufferMapIt->second = buffer;
}
else
{
mBufferHandleAllocator.reserve(handle);
mBufferMap[handle] = buffer;
}
} }
} }
void ResourceManager::checkTextureAllocation(GLuint handle, GLenum type) void ResourceManager::checkTextureAllocation(GLuint texture, GLenum type)
{ {
if (handle != 0) if (!getTexture(texture) && texture != 0)
{
auto textureMapIt = mTextureMap.find(handle);
bool handleAllocated = (textureMapIt != mTextureMap.end());
if (handleAllocated && textureMapIt->second != nullptr)
{
return;
}
Texture *texture = new Texture(mFactory->createTexture(type), handle, type);
texture->addRef();
if (handleAllocated)
{
textureMapIt->second = texture;
}
else
{ {
mTextureHandleAllocator.reserve(handle); Texture *textureObject = new Texture(mFactory->createTexture(type), texture, type);
mTextureMap[handle] = texture; mTextureMap[texture] = textureObject;
} textureObject->addRef();
} }
} }
void ResourceManager::checkRenderbufferAllocation(GLuint handle) void ResourceManager::checkRenderbufferAllocation(GLuint renderbuffer)
{ {
if (handle != 0) if (renderbuffer != 0 && !getRenderbuffer(renderbuffer))
{
auto renderbufferMapIt = mRenderbufferMap.find(handle);
bool handleAllocated = (renderbufferMapIt != mRenderbufferMap.end());
if (handleAllocated && renderbufferMapIt->second != nullptr)
{ {
return; Renderbuffer *renderbufferObject = new Renderbuffer(mFactory->createRenderbuffer(), renderbuffer);
} mRenderbufferMap[renderbuffer] = renderbufferObject;
renderbufferObject->addRef();
Renderbuffer *renderbuffer = new Renderbuffer(mFactory->createRenderbuffer(), handle);
renderbuffer->addRef();
if (handleAllocated)
{
renderbufferMapIt->second = renderbuffer;
}
else
{
mRenderbufferHandleAllocator.reserve(handle);
mRenderbufferMap[handle] = renderbuffer;
}
} }
} }
...@@ -444,7 +393,6 @@ void ResourceManager::checkSamplerAllocation(GLuint sampler) ...@@ -444,7 +393,6 @@ void ResourceManager::checkSamplerAllocation(GLuint sampler)
Sampler *samplerObject = new Sampler(sampler); Sampler *samplerObject = new Sampler(sampler);
mSamplerMap[sampler] = samplerObject; mSamplerMap[sampler] = samplerObject;
samplerObject->addRef(); samplerObject->addRef();
// Samplers cannot be created via Bind
} }
} }
......
...@@ -68,9 +68,9 @@ class ResourceManager ...@@ -68,9 +68,9 @@ class ResourceManager
void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer);
void checkBufferAllocation(GLuint handle); void checkBufferAllocation(unsigned int buffer);
void checkTextureAllocation(GLuint handle, GLenum type); void checkTextureAllocation(GLuint texture, GLenum type);
void checkRenderbufferAllocation(GLuint handle); void checkRenderbufferAllocation(GLuint renderbuffer);
void checkSamplerAllocation(GLuint sampler); void checkSamplerAllocation(GLuint sampler);
bool isSampler(GLuint sampler); bool isSampler(GLuint sampler);
...@@ -78,8 +78,6 @@ class ResourceManager ...@@ -78,8 +78,6 @@ class ResourceManager
private: private:
DISALLOW_COPY_AND_ASSIGN(ResourceManager); DISALLOW_COPY_AND_ASSIGN(ResourceManager);
void createTextureInternal(GLuint handle);
rx::ImplFactory *mFactory; rx::ImplFactory *mFactory;
std::size_t mRefCount; std::size_t mRefCount;
......
//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Unit tests for ResourceManager.
//
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "angle_unittests_utils.h"
#include "libANGLE/ResourceManager.h"
using namespace rx;
using namespace gl;
namespace
{
class MockFactory : public NullFactory
{
public:
MOCK_METHOD0(createBuffer, BufferImpl*());
MOCK_METHOD1(createTexture, TextureImpl*(GLenum));
MOCK_METHOD0(createRenderbuffer, RenderbufferImpl*());
};
class ResourceManagerTest : public testing::Test
{
protected:
void SetUp() override
{
mResourceManager = new ResourceManager(&mMockFactory);
}
void TearDown() override
{
SafeDelete(mResourceManager);
}
MockFactory mMockFactory;
ResourceManager *mResourceManager;
};
TEST_F(ResourceManagerTest, ReallocateBoundTexture)
{
EXPECT_CALL(mMockFactory, createTexture(GL_TEXTURE_2D)).Times(1).RetiresOnSaturation();
mResourceManager->checkTextureAllocation(1, GL_TEXTURE_2D);
GLuint newTexture = mResourceManager->createTexture();
EXPECT_NE(1u, newTexture);
}
TEST_F(ResourceManagerTest, ReallocateBoundBuffer)
{
EXPECT_CALL(mMockFactory, createBuffer()).Times(1).RetiresOnSaturation();
mResourceManager->checkBufferAllocation(1);
GLuint newBuffer = mResourceManager->createBuffer();
EXPECT_NE(1u, newBuffer);
}
TEST_F(ResourceManagerTest, ReallocateBoundRenderbuffer)
{
EXPECT_CALL(mMockFactory, createRenderbuffer()).Times(1).RetiresOnSaturation();
mResourceManager->checkRenderbufferAllocation(1);
GLuint newRenderbuffer = mResourceManager->createRenderbuffer();
EXPECT_NE(1u, newRenderbuffer);
}
}
...@@ -18,12 +18,9 @@ ...@@ -18,12 +18,9 @@
'<(angle_path)/src/common/Optional_unittest.cpp', '<(angle_path)/src/common/Optional_unittest.cpp',
'<(angle_path)/src/libANGLE/Config_unittest.cpp', '<(angle_path)/src/libANGLE/Config_unittest.cpp',
'<(angle_path)/src/libANGLE/Fence_unittest.cpp', '<(angle_path)/src/libANGLE/Fence_unittest.cpp',
'<(angle_path)/src/libANGLE/HandleAllocator_unittest.cpp',
'<(angle_path)/src/libANGLE/ImageIndexIterator_unittest.cpp', '<(angle_path)/src/libANGLE/ImageIndexIterator_unittest.cpp',
'<(angle_path)/src/libANGLE/ResourceManager_unittest.cpp',
'<(angle_path)/src/libANGLE/Surface_unittest.cpp', '<(angle_path)/src/libANGLE/Surface_unittest.cpp',
'<(angle_path)/src/libANGLE/TransformFeedback_unittest.cpp', '<(angle_path)/src/libANGLE/TransformFeedback_unittest.cpp',
'<(angle_path)/src/tests/angle_unittests_utils.h',
'<(angle_path)/src/tests/compiler_tests/API_test.cpp', '<(angle_path)/src/tests/compiler_tests/API_test.cpp',
'<(angle_path)/src/tests/compiler_tests/CollectVariables_test.cpp', '<(angle_path)/src/tests/compiler_tests/CollectVariables_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ConstantFolding_test.cpp', '<(angle_path)/src/tests/compiler_tests/ConstantFolding_test.cpp',
...@@ -67,7 +64,6 @@ ...@@ -67,7 +64,6 @@
'<(angle_path)/include', '<(angle_path)/include',
'<(angle_path)/src', '<(angle_path)/src',
'<(angle_path)/src/compiler/preprocessor', '<(angle_path)/src/compiler/preprocessor',
'<(angle_path)/src/tests',
], ],
'sources': 'sources':
[ [
......
//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// angle_unittests_utils.h:
// Helpers for mocking and unit testing.
#ifndef TESTS_ANGLE_UNITTESTS_UTILS_H_
#define TESTS_ANGLE_UNITTESTS_UTILS_H_
#include "libANGLE/renderer/ImplFactory.h"
namespace rx
{
// Useful when mocking a part of the ImplFactory class
class NullFactory : public ImplFactory
{
public:
NullFactory() {}
// Shader creation
CompilerImpl *createCompiler(const gl::Data &data) override { return nullptr; }
ShaderImpl *createShader(GLenum type) override { return nullptr; }
ProgramImpl *createProgram() override { return nullptr; }
// Framebuffer creation
DefaultAttachmentImpl *createDefaultAttachment(GLenum type, egl::Surface *surface) override { return nullptr; }
FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override { return nullptr; }
// Texture creation
TextureImpl *createTexture(GLenum target) override { return nullptr; }
// Renderbuffer creation
RenderbufferImpl *createRenderbuffer() override { return nullptr; }
// Buffer creation
BufferImpl *createBuffer() override { return nullptr; }
// Vertex Array creation
VertexArrayImpl *createVertexArray() override { return nullptr; }
// Query and Fence creation
QueryImpl *createQuery(GLenum type) override { return nullptr; }
FenceNVImpl *createFenceNV() override { return nullptr; }
FenceSyncImpl *createFenceSync() override { return nullptr; }
// Transform Feedback creation
TransformFeedbackImpl *createTransformFeedback() override { return nullptr; }
DISALLOW_COPY_AND_ASSIGN(NullFactory);
};
}
#endif // TESTS_ANGLE_UNITTESTS_UTILS_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment