Beatmup
content_lock.cpp
Go to the documentation of this file.
1 /*
2  Beatmup image and signal processing library
3  Copyright (C) 2020, lnstadrum
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "content_lock.h"
20 #include "abstract_bitmap.h"
21 #include "../gpu/pipeline.h"
22 #ifdef BEATMUP_DEBUG
23 #include "../debug.h"
24 #endif
25 
26 using namespace Beatmup;
27 
28 
30 #ifdef BEATMUP_DEBUG
31  if (!bitmaps.empty())
32  BEATMUP_DEBUG_E("Destroying a content lock having %d locked bitmaps", (int)bitmaps.size());
33 #endif
34 }
35 
36 
38 #ifdef BEATMUP_DEBUG
39  DebugAssertion::check(!bitmap->isDirty(), "Reading a dirty bitmap");
40  if (target == ProcessingTarget::GPU)
41  DebugAssertion::check(gpu, "Cannot lock a bitmap on GPU: no graphic pipeline instance available");
42 #endif
43 
44  bool transferToGpuNeeded = false;
45  bool transferFromGpuNeeded = false;
46 
47  auto it = bitmaps.find(bitmap);
48  if (it == bitmaps.end()) {
49  // creating a lock descriptor
51  true, false,
52  target == ProcessingTarget::CPU,
53  target == ProcessingTarget::GPU,
54  false,
55  1
56  };
57 
58  // pixel transfer to GPU is needed if the bitmap is not up to date on GPU
59  transferToGpuNeeded = lock.gpu && !bitmap->isUpToDate(ProcessingTarget::GPU);
60  transferFromGpuNeeded = lock.cpu && !bitmap->isUpToDate(ProcessingTarget::CPU);
61 
62  // locking pixel data in RAM
63  if (lock.cpu || transferToGpuNeeded || transferFromGpuNeeded) {
65  lock.isDataLocked = true;
66  }
67 
68  bitmaps.emplace(bitmap, lock);
69  }
70 
71  else {
72  // already locked, just increase reference counter
73  auto& lock = it->second;
74 
75  RuntimeError::check(((target == ProcessingTarget::CPU) == lock.cpu) && ((target == ProcessingTarget::GPU) == lock.gpu),
76  "Lock target mismatch: a bitmap was previously locked for a different target");
77 
78  // It is allowed to lock a bitmap for writing first and for reading later.
79  if (!lock.read) {
80  transferToGpuNeeded = lock.gpu && !bitmap->isUpToDate(ProcessingTarget::GPU);
81  transferFromGpuNeeded = lock.cpu && !bitmap->isUpToDate(ProcessingTarget::CPU);
82 
83  if (!lock.isDataLocked && (transferToGpuNeeded || transferFromGpuNeeded)) {
85  lock.isDataLocked = true;
86  }
87 
88  lock.read = true;
89  }
90  lock.refs++;
91  }
92 
93  // do pixel transfer if required
94  if (transferToGpuNeeded)
95  gpu->pushPixels(*bitmap);
96  else if (transferFromGpuNeeded)
97  gpu->pullPixels(*bitmap);
98 }
99 
100 
102 #ifdef BEATMUP_DEBUG
103  if (target == ProcessingTarget::GPU)
104  DebugAssertion::check(gpu, "Cannot lock a bitmap on GPU: no graphic pipeline instance available");
105 #endif
106 
107  auto it = bitmaps.find(bitmap);
108  if (it == bitmaps.end()) {
109  // creating a lock descriptor
111  false, true,
112  target == ProcessingTarget::CPU,
113  target == ProcessingTarget::GPU,
114  target == ProcessingTarget::CPU, // data is locked if writing on CPU
115  1
116  };
117  bitmaps.emplace(bitmap, lock);
118 
119  // locking pixel data in RAM
120  if (lock.isDataLocked)
122  }
123 
124  else {
125  // already locked, just increase reference counter
126  auto& lock = it->second;
127 
128  if (lock.read && !lock.write)
129  throw RuntimeError("Cannot a bitmap for writing: it was locked for reading before. Lock it for writing first.");
130 
131  // lock data if needed and not yet
132  if (!lock.isDataLocked && target == ProcessingTarget::CPU) {
134  lock.isDataLocked = true;
135  }
136 
137  lock.gpu |= (target == ProcessingTarget::GPU);
138  lock.cpu |= (target == ProcessingTarget::CPU);
139 
140  lock.refs++;
141  }
142 }
143 
144 
146  auto it = bitmaps.find(bitmap);
147 #ifdef BEATMUP_DEBUG
148  DebugAssertion::check(it != bitmaps.end(), "Trying to unlock a bitmap that is not locked.");
149 #endif
150 
151  auto& lock = it->second;
152  lock.refs--;
153  if (lock.refs == 0) {
154  if (lock.isDataLocked)
156 
157  if (lock.write) {
160  }
161 
162  bitmaps.erase(it);
163  }
164 }
165 
166 
168  for (auto it : bitmaps) {
169  auto& lock = it.second;
170  if (lock.isDataLocked)
171  it.first->unlockPixelData();
172 
173  if (lock.write) {
174  it.first->upToDate[ProcessingTarget::CPU] = lock.cpu;
175  it.first->upToDate[ProcessingTarget::GPU] = lock.gpu;
176  }
177  }
178 
179  bitmaps.clear();
180 }
A very basic class for any image.
bool isDirty() const
Returns true if the bitmap does not contain any valid content.
bool isUpToDate(ProcessingTarget) const
bool upToDate[2]
bitmap up-to-date state on CPU and GPU
void unlock(AbstractBitmap *bitmap)
Drops a lock to the bitmap.
void lock(GraphicPipeline *gpu, AbstractBitmap *input, AbstractBitmap *output)
Definition: content_lock.h:84
std::map< AbstractBitmap *, LockDescriptor > bitmaps
Definition: content_lock.h:45
void readLock(GraphicPipeline *gpu, AbstractBitmap *bitmap, ProcessingTarget target)
Locks content of a bitmap for reading using a specific processing target device.
void writeLock(GraphicPipeline *gpu, AbstractBitmap *bitmap, ProcessingTarget target)
Locks content of a bitmap for writing using a specific processing target device.
void unlockAll()
Unlocks all the locked bitmaps unconditionally.
Internal low-level GPU control API.
Definition: pipeline.h:33
void pullPixels(AbstractBitmap &bitmap)
Transfers bitmap pixels from GPU to CPU.
Definition: pipeline.cpp:921
void pushPixels(AbstractBitmap &bitmap)
Transfers bitmap pixels from CPU to GPU.
Definition: pipeline.cpp:926
void unlockPixelData()
Unlocks access to the CPU memory buffer containing pixel data.
void lockPixelData()
Locks access to the CPU memory buffer containing pixel data.
static void check(const bool condition, const std::string &message)
Definition: exception.h:64
#define BEATMUP_DEBUG_E(...)
Definition: debug.h:34
ProcessingTarget
Definition: basic_types.h:55
Beatmup::InternalBitmap * bitmap