164 lines
6.7 KiB
C
164 lines
6.7 KiB
C
|
/**
|
||
|
* PANDA 3D SOFTWARE
|
||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||
|
*
|
||
|
* All use of this software is subject to the terms of the revised BSD
|
||
|
* license. You should have received a copy of this license along
|
||
|
* with this source code in a file named "LICENSE."
|
||
|
*
|
||
|
* @file pipelineCycler.h
|
||
|
* @author drose
|
||
|
* @date 2002-02-21
|
||
|
*/
|
||
|
|
||
|
#ifndef PIPELINECYCLER_H
|
||
|
#define PIPELINECYCLER_H
|
||
|
|
||
|
#include "pandabase.h"
|
||
|
#include "pipelineCyclerBase.h"
|
||
|
#include "cyclerHolder.h"
|
||
|
#include "thread.h"
|
||
|
|
||
|
/**
|
||
|
* This class maintains different copies of a page of data between stages of
|
||
|
* the graphics pipeline (or any other pipelining context).
|
||
|
*
|
||
|
* The class object maintains up to n copies of a CycleData structure, one for
|
||
|
* each stage of the pipeline. The head of the pipeline is responsible for
|
||
|
* making changes to its copy, which are then cycled through the pipeline at
|
||
|
* each frame.
|
||
|
*
|
||
|
* To access the data, you must first ask for a readable pointer. In order to
|
||
|
* make changes to the data, you must ask for a writable pointer. Both kinds
|
||
|
* of pointers should be released when you are done, as a sanity check. The
|
||
|
* CycleDataReader and CycleDataWriter classes transparently handle this.
|
||
|
*
|
||
|
* If pipelining support is not enabled at compile time (that is,
|
||
|
* DO_PIPELINING is not defined), this object compiles to a minimum object
|
||
|
* that presents the same interface but with minimal runtime overhead.
|
||
|
*
|
||
|
* We define this as a struct instead of a class to guarantee byte placement
|
||
|
* within the object, so that (particularly for the trivial implementation)
|
||
|
* the inherited struct's data is likely to be placed by the compiler at the
|
||
|
* "this" pointer.
|
||
|
*/
|
||
|
template<class CycleDataType>
|
||
|
struct PipelineCycler : public PipelineCyclerBase {
|
||
|
public:
|
||
|
INLINE PipelineCycler(Pipeline *pipeline = nullptr);
|
||
|
INLINE PipelineCycler(CycleDataType &&initial_data, Pipeline *pipeline = nullptr);
|
||
|
|
||
|
INLINE PipelineCycler(const PipelineCycler<CycleDataType> ©);
|
||
|
INLINE void operator = (const PipelineCycler<CycleDataType> ©);
|
||
|
|
||
|
INLINE const CycleDataType *read_unlocked(Thread *current_thread) const;
|
||
|
INLINE const CycleDataType *read(Thread *current_thread) const;
|
||
|
INLINE CycleDataType *write(Thread *current_thread);
|
||
|
INLINE CycleDataType *write_upstream(bool force_to_0, Thread *current_thread);
|
||
|
INLINE CycleDataType *elevate_read(const CycleDataType *pointer, Thread *current_thread);
|
||
|
INLINE CycleDataType *elevate_read_upstream(const CycleDataType *pointer, bool force_to_0, Thread *current_thread);
|
||
|
|
||
|
INLINE const CycleDataType *read_stage_unlocked(int pipeline_stage) const;
|
||
|
INLINE const CycleDataType *read_stage(int pipeline_stage, Thread *current_thread) const;
|
||
|
INLINE CycleDataType *elevate_read_stage(int pipeline_stage, const CycleDataType *pointer, Thread *current_thread);
|
||
|
INLINE CycleDataType *elevate_read_stage_upstream(int pipeline_stage, const CycleDataType *pointer, bool force_to_0, Thread *current_thread);
|
||
|
INLINE CycleDataType *write_stage_upstream(int pipeline_stage, bool force_to_0, Thread *current_thread);
|
||
|
INLINE CycleDataType *write_stage(int pipeline_stage, Thread *current_thread);
|
||
|
|
||
|
INLINE CycleDataType *cheat() const;
|
||
|
|
||
|
#ifndef DO_PIPELINING
|
||
|
private:
|
||
|
// If we are *not* compiling in support for pipelining, we just store the
|
||
|
// CycleData object right here. No pointers needed.
|
||
|
CycleDataType _typed_data;
|
||
|
#endif // !DO_PIPELINING
|
||
|
};
|
||
|
|
||
|
// These macros are handy for iterating through the set of pipeline stages.
|
||
|
// They're particularly useful for updating cache values upstream of the
|
||
|
// current stage, or for removing bad pointers from all stages of the
|
||
|
// pipeline. In each case, the variable pipeline_stage is defined within the
|
||
|
// loop to be the current stage of the pipeline traversed by the loop.
|
||
|
#ifdef DO_PIPELINING
|
||
|
|
||
|
// Iterates through all of the pipeline stages upstream of the current stage,
|
||
|
// but not including the current stage.
|
||
|
#define OPEN_ITERATE_UPSTREAM_ONLY(cycler, current_thread) { \
|
||
|
CyclerHolder cholder(cycler); \
|
||
|
int pipeline_stage; \
|
||
|
for (pipeline_stage = current_thread->get_pipeline_stage() - 1; \
|
||
|
pipeline_stage >= 0; \
|
||
|
--pipeline_stage)
|
||
|
|
||
|
#define CLOSE_ITERATE_UPSTREAM_ONLY(cycler) \
|
||
|
}
|
||
|
|
||
|
// Iterates through all of the pipeline stages upstream of the current stage,
|
||
|
// and including the current stage.
|
||
|
#define OPEN_ITERATE_CURRENT_AND_UPSTREAM(cycler, current_thread) { \
|
||
|
CyclerHolder cholder(cycler); \
|
||
|
int pipeline_stage; \
|
||
|
for (pipeline_stage = current_thread->get_pipeline_stage(); \
|
||
|
pipeline_stage >= 0; \
|
||
|
--pipeline_stage)
|
||
|
|
||
|
#define CLOSE_ITERATE_CURRENT_AND_UPSTREAM(cycler) \
|
||
|
}
|
||
|
|
||
|
// As above, but without holding the cycler lock during the loop.
|
||
|
#define OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler, current_thread) { \
|
||
|
int pipeline_stage; \
|
||
|
for (pipeline_stage = current_thread->get_pipeline_stage(); \
|
||
|
pipeline_stage >= 0; \
|
||
|
--pipeline_stage)
|
||
|
|
||
|
#define CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler) \
|
||
|
}
|
||
|
|
||
|
// Iterates through all of the pipeline stages.
|
||
|
#define OPEN_ITERATE_ALL_STAGES(cycler) { \
|
||
|
int pipeline_stage; \
|
||
|
for (pipeline_stage = (cycler).get_num_stages() - 1; \
|
||
|
pipeline_stage >= 0; \
|
||
|
--pipeline_stage)
|
||
|
|
||
|
#define CLOSE_ITERATE_ALL_STAGES(cycler) \
|
||
|
}
|
||
|
|
||
|
#else // DO_PIPELINING
|
||
|
|
||
|
// These are trivial implementations of the above macros, defined when
|
||
|
// pipelining is not enabled, that simply operate on stage 0 without bothering
|
||
|
// to create a for loop.
|
||
|
#define OPEN_ITERATE_UPSTREAM_ONLY(cycler, current_thread) \
|
||
|
if (false) { \
|
||
|
const int pipeline_stage = -1;
|
||
|
|
||
|
#define CLOSE_ITERATE_UPSTREAM_ONLY(cycler) \
|
||
|
}
|
||
|
|
||
|
#define OPEN_ITERATE_CURRENT_AND_UPSTREAM(cycler, current_thread) { \
|
||
|
const int pipeline_stage = 0; \
|
||
|
|
||
|
#define CLOSE_ITERATE_CURRENT_AND_UPSTREAM(cycler) \
|
||
|
}
|
||
|
|
||
|
#define OPEN_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler, current_thread) { \
|
||
|
const int pipeline_stage = 0; \
|
||
|
|
||
|
#define CLOSE_ITERATE_CURRENT_AND_UPSTREAM_NOLOCK(cycler) \
|
||
|
}
|
||
|
|
||
|
#define OPEN_ITERATE_ALL_STAGES(cycler) { \
|
||
|
const int pipeline_stage = 0; \
|
||
|
|
||
|
#define CLOSE_ITERATE_ALL_STAGES(cycler) \
|
||
|
}
|
||
|
|
||
|
#endif // DO_PIPELINING
|
||
|
|
||
|
#include "pipelineCycler.I"
|
||
|
|
||
|
#endif
|