test driven brainstorming: using a BufferProvider

This commit is contained in:
Fischlurch 2011-09-17 01:50:11 +02:00
parent 8016547d9c
commit 1f13931640
4 changed files with 195 additions and 2 deletions

View file

@ -0,0 +1,67 @@
/*
DIAGNOSTIC-BUFFER-PROVIDER.hpp - helper for testing against the BufferProvider interface
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file diagnostic-buffer-provider.hpp
** An facility for writing unit-tests targetting the BufferProvider interface.
**
** @see buffer-provider-protocol-test.cpp
*/
#ifndef PROC_ENGINE_DIAGNOSTIC_BUFFR_PROVIDER_H
#define PROC_ENGINE_DIAGNOSTIC_BUFFR_PROVIDER_H
#include "lib/error.hpp"
#include "proc/engine/buffer-provider.hpp"
#include <boost/noncopyable.hpp>
namespace engine {
/********************************************************************
* Helper for unit tests: Buffer provider reference implementation.
*
* @todo write type comment
*/
class DiagnosticBufferProvider
: public BufferProvider
{
public:
/** build a new Diagnostic Buffer Provider instance,
* discard the existing one. Use the static query API
* for investigating collected data. */
static BufferProvider&
build()
{
UNIMPLEMENTED ("Diagnostic Buffer Provider instance");
}
private:
};
} // namespace engine
#endif

View file

@ -2,6 +2,11 @@ TESTING "Component Test Suite: Render Engine parts" ./test-components --group=en
PLANNED "BufferProviderProtocol_test" Buffer provider diagnostics <<END
return: 0
END
PLANNED "BuffTable_test" BuffTable_test <<END
return: 0
END

View file

@ -0,0 +1,121 @@
/*
BufferProviderProtocol(Test) - demonstration of buffer provider usage cycle
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "lib/error.hpp"
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
//#include "lib/util.hpp"
//#include "proc/play/diagnostic-output-slot.hpp"
#include "proc/engine/diagnostic-buffer-provider.hpp"
#include "proc/engine/buffhandle.hpp"
//#include <boost/format.hpp>
//#include <iostream>
//using boost::format;
//using std::string;
//using std::cout;
namespace engine{
namespace test {
// using lib::AllocationCluster;
// using mobject::session::PEffect;
using ::engine::BuffHandle;
using lumiera::error::LUMIERA_ERROR_LIFECYCLE;
namespace { // Test fixture
}
/*******************************************************************
* @test verify the OutputSlot interface and base implementation
* by performing full data exchange cycle. This is a
* kind of "dry run" for documentation purposes,
* both the actual OutputSlot implementation
* as the client using this slot are Mocks.
*/
class BufferProviderProtocol_test : public Test
{
virtual void
run (Arg)
{
UNIMPLEMENTED ("build a diagnostic buffer provider and perform a full lifecycle");
verifyStandardCase();
}
void
verifySimpleUsage()
{
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #829
// Create Test fixture.
// In real usage, a suitable memory/frame/buffer provider
// will be preconfigured, depending on the usage context
BufferProvider& provider = DiagnosticBufferProvider::build();
BuffHandle buff = provider.lockBufferFor<TestFrame>();
CHECK (buff.isValid());
CHECK (sizeof(TestFrame) <= buff.size());
buff.create<TestFrame>() = testData(0);
TestFrame* storage = *buff;
CHECK (testData(0) == *storage);
buff.release();
CHECK (!buff.isValid());
VERIFY_ERROR (LIFECYCLE, *buff );
DiagnosticBufferProvider checker = DiagnosticBufferProvider::access(provider);
CHECK (checker.buffer_was_used (0));
CHECK (checker.buffer_was_closed (0));
CHECK (checker.object_was_attached<TestFrame> ());
CHECK (checker.object_was_destroyed<TestFrame> ());
CHECK (testData(0) == checker.accessStorage (0));
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #829
}
void
verifyStandardCase()
{
// Create Test fixture.
// In real usage, a suitable memory/frame/buffer provider
// will be preconfigured, depending on the usage context
BufferProvider& provider = DiagnosticBufferProvider::build();
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #829
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #829
}
};
/** Register this test class... */
LAUNCHER (BufferProviderProtocol_test, "unit player");
}} // namespace engine::test

View file

@ -1121,7 +1121,7 @@ Mostly, the //client code,// i.e. code in need of using buffers, can access some
</pre>
</div>
<div title="BufferProvider" modifier="Ichthyostega" modified="201109151410" created="201107082330" tags="Rendering spec draft" changecount="12">
<div title="BufferProvider" modifier="Ichthyostega" modified="201109162209" created="201107082330" tags="Rendering spec draft" changecount="13">
<pre>It turns out that -- throughout the render engine implementation -- we never need direct access to the buffers holding media data. Buffers are just some entity to be //managed,// i.e. &quot;allocated&quot;, &quot;locked&quot; and &quot;released&quot;; the //actual meaning of these operations can be left to the implementation.// The code within the render engine just pushes around ''smart-prt like handles''. These [[buffer handles|BuffHandle]] act as a front-end, being created by and linked to a buffer provider implementation. There is no need to manage the lifecycle of buffers automatically, because the use of buffers is embedded into the render calculation cycle, which follows a rather strict protocol anyway. Relying on the [[capabilities of the scheduler|SchedulerRequirements]], the sequence of individual jobs in the engine ensures...
* that the availability of a buffer was ensured prior to planning a job (&quot;buffer allocation&quot;)
* that a buffer handle was obtained (&quot;locked&quot;) prior to any operation requiring a buffer
@ -1132,7 +1132,7 @@ While BufferProvider is an interface meant to be backed by various different kin
;announcing
:client code may announce beforehand that it expects to get a certain amount of buffers. Usually this causes some allocations (or similar mechanisms to ensure the avialability) to happen right away; the BufferProvider will then return the actual number of buffers guraanteed to be available. This announcing step is optional an can happen anytime before or even after using the buffers and it can be repeated with different values to adjust to changing requirements. (Currently 9/2011 this is meant to be global for the whole BufferProvider, but it might happen that we need to break that down to individual clients)
;locking
:this operation actually makes a buffer available for a specific client and returns a [[buffer handle|BuffHandle]]. The corresponding buffer is marked as used and can't be locked again until released. If necessary, the BufferProvider might at that point allocate memory to accomodate (especially when the buffers weren't announced beforehand). The locking might fail and raise an exception. To support additional sanity checks, the client may provide a token-ID with the lock-operation. This token may be retrieved later and it may be used to ensure the buffer is actually locked for //this token.//
:this operation actually makes a buffer available for a specific client and returns a [[buffer handle|BuffHandle]]. The corresponding buffer is marked as used and can't be locked again until released. If necessary, at that point the BufferProvider might allocate memory to accomodate (especially when the buffers weren't announced beforehand). The locking may fail and raise an exception. You may expect failure to be unlikely when buffers have been //anounced beforehand.// To support additional sanity checks, the client may provide a token-ID with the lock-operation. This token may be retrieved later and it may be used to ensure the buffer is actually locked for //this token.//
;attaching
:optionally the client may attach an object to a locked buffer. This object is placement-constructed into the buffer and will be automatically destroyed when releasing the buffer. Alternatively, the client may provide a pair of constructor- / destructor-functors, which will be invoked in a similar manner. This allows e.g. to install descriptor structures within the buffer, as required by an external library.
;releasing