CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HW/BufferQueue.h
Views: 1401
1
// Copyright (c) 2013- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#pragma once
19
20
#include <map>
21
#include <cstdint>
22
#include <cstring>
23
#include "Common/Log.h"
24
#include "Common/Serialize/Serializer.h"
25
26
struct BufferQueue {
27
BufferQueue(int size = 0x20000) {
28
alloc(size);
29
}
30
31
~BufferQueue() {
32
delete [] bufQueue;
33
}
34
35
bool alloc(int size) {
36
_assert_(size > 0);
37
delete [] bufQueue;
38
bufQueue = new unsigned char[size];
39
bufQueueSize = size;
40
clear();
41
return true;
42
}
43
44
void clear() {
45
start = 0;
46
end = 0;
47
filled = 0;
48
}
49
50
inline int getQueueSize() {
51
return filled;
52
}
53
54
inline int getRemainSize() {
55
return bufQueueSize - getQueueSize();
56
}
57
58
bool push(const unsigned char *buf, int addsize, s64 pts = 0) {
59
int space = getRemainSize();
60
if (space < addsize || addsize < 0)
61
return false;
62
savePts(pts);
63
if (end + addsize <= bufQueueSize) {
64
// If end is before start, there's enough space. Otherwise, we're nearing the queue size.
65
memcpy(bufQueue + end, buf, addsize);
66
end += addsize;
67
if (end == bufQueueSize)
68
end = 0;
69
} else {
70
// Time to wrap end. Fill what remains, then fill before start.
71
_assert_(end >= start);
72
int firstSize = bufQueueSize - end;
73
memcpy(bufQueue + end, buf, firstSize);
74
memcpy(bufQueue, buf + firstSize, addsize - firstSize);
75
end = addsize - firstSize;
76
}
77
filled += addsize;
78
verifyQueueSize();
79
return true;
80
}
81
82
int pop_front(unsigned char *buf, int wantedsize, s64 *pts = nullptr) {
83
if (wantedsize <= 0)
84
return 0;
85
int bytesgot = getQueueSize();
86
if (wantedsize < bytesgot)
87
bytesgot = wantedsize;
88
if (pts != nullptr) {
89
*pts = findPts(bytesgot);
90
}
91
92
int firstSize = bufQueueSize - start;
93
if (buf) {
94
if (bytesgot <= firstSize) {
95
memcpy(buf, bufQueue + start, bytesgot);
96
} else {
97
memcpy(buf, bufQueue + start, firstSize);
98
memcpy(buf + firstSize, bufQueue, bytesgot - firstSize);
99
}
100
}
101
if (bytesgot <= firstSize)
102
start += bytesgot;
103
else
104
start = bytesgot - firstSize;
105
if (start == bufQueueSize)
106
start = 0;
107
filled -= bytesgot;
108
verifyQueueSize();
109
return bytesgot;
110
}
111
112
int get_front(unsigned char *buf, int wantedsize) {
113
if (wantedsize <= 0)
114
return 0;
115
int bytesgot = getQueueSize();
116
if (wantedsize < bytesgot)
117
bytesgot = wantedsize;
118
int firstSize = bufQueueSize - start;
119
if (bytesgot <= firstSize) {
120
memcpy(buf, bufQueue + start, bytesgot);
121
} else {
122
memcpy(buf, bufQueue + start, firstSize);
123
memcpy(buf + firstSize, bufQueue, bytesgot - firstSize);
124
}
125
return bytesgot;
126
}
127
128
void DoState(PointerWrap &p);
129
130
private:
131
void savePts(u64 pts) {
132
if (pts != 0) {
133
ptsMarks[end] = pts;
134
}
135
}
136
137
u64 findPts(std::map<u32, s64>::iterator earliest, std::map<u32, s64>::iterator latest) {
138
u64 pts = 0;
139
// Take the first one, that is the pts of this packet.
140
if (earliest != latest) {
141
pts = earliest->second;
142
}
143
ptsMarks.erase(earliest, latest);
144
return pts;
145
}
146
147
u64 findPts(int packetSize) {
148
auto earliest = ptsMarks.lower_bound(start);
149
auto latest = ptsMarks.lower_bound(start + packetSize);
150
151
u64 pts = findPts(earliest, latest);
152
153
// If it wraps around, we have to look at the other half too.
154
if (start + packetSize > bufQueueSize) {
155
earliest = ptsMarks.begin();
156
latest = ptsMarks.lower_bound(start + packetSize - bufQueueSize);
157
// This also clears the range, so we always call on wrap.
158
u64 latePts = findPts(earliest, latest);
159
if (pts == 0)
160
pts = latePts;
161
}
162
163
return pts;
164
}
165
166
inline int calcQueueSize() {
167
if (end < start) {
168
return bufQueueSize + end - start;
169
}
170
return end - start;
171
}
172
173
inline void verifyQueueSize() {
174
_assert_(calcQueueSize() == filled || (end == start && filled == bufQueueSize));
175
}
176
177
uint8_t *bufQueue = nullptr;
178
// Model: end may be less than start, indicating the space between end and start is free.
179
// If end equals start, we're empty.
180
int start = 0, end = 0;
181
int filled = 0;
182
int bufQueueSize = 0;
183
184
std::map<u32, s64> ptsMarks;
185
};
186
187