Skip to content

Commit 027070b

Browse files
committed
MiniAL GUS deallocation. MiniAL buffer reference counting.
Unit test for reference counting.
1 parent 459175b commit 027070b

9 files changed

Lines changed: 256 additions & 28 deletions

File tree

src/gamemng.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,13 +422,21 @@ void Gamemng::init(const char* maps_def, const char* objs_def, const char* cars_
422422
swapArrayLE16(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
423423
tweakLoop(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
424424
alBufferData(p_cars[i].p_engine0_sample, AL_FORMAT_MONO16, gbuff_in.fbuffptr(), gbuff_in.fbuffsz(), smallSampleRam() ? 11025 : 22050);
425+
if (alGetError() == AL_OUT_OF_MEMORY)
426+
{
427+
fprintf(stderr, "AL buffer data allocation error\n");
428+
}
425429
gbuff_in.fclose();
426430

427431
gbuff_in.f_open(p_cars[i].fname_sample_engine1, "rb");if (smallSampleRam())gbuff_in.downsampleAudio16();
428432
alGenBuffers(1, &(p_cars[i].p_engine1_sample)); global_al_buffers.push_back(p_cars[i].p_engine1_sample);
429433
swapArrayLE16(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
430434
tweakLoop(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
431435
alBufferData(p_cars[i].p_engine1_sample, AL_FORMAT_MONO16, gbuff_in.fbuffptr(), gbuff_in.fbuffsz(), smallSampleRam() ? 11025 : 22050);
436+
if (alGetError() == AL_OUT_OF_MEMORY)
437+
{
438+
fprintf(stderr, "AL buffer data allocation error\n");
439+
}
432440
gbuff_in.fclose();
433441
}
434442
}

src/minial_gus.cpp

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#include "gus.h"
77

8+
#define GUS_ALLOC_DEBUG_LOG 0
9+
810
MinialGUS::MinialGUS(ALint monoSources)
911
{
1012
m_gusVoices = monoSources;
@@ -70,6 +72,7 @@ uint32_t MinialGUS::gusAlloc(uint32_t len)
7072
uint32_t oldStart = fm.first;
7173
freeMap.erase(oldStart);
7274
freeMap[oldStart + len] = oldLen - len;
75+
allocMap[oldStart] = len;
7376
return oldStart;
7477
}
7578
}
@@ -82,7 +85,57 @@ void MinialGUS::gusFree(uint32_t pos)
8285
{
8386
return;
8487
}
85-
/*TODO*/
88+
auto it = allocMap.find(pos);
89+
if (it == allocMap.end())
90+
{
91+
return;
92+
}
93+
freeMap[it->first] = it->second;
94+
allocMap.erase(pos);
95+
gusDefrag();
96+
}
97+
98+
void MinialGUS::gusDefrag(void)
99+
{
100+
for (;;)
101+
{
102+
uint32_t thisAddr = 0;
103+
uint32_t nextAddr = 0;
104+
uint32_t newLen = 0;
105+
bool found = false;
106+
for (auto it : freeMap)
107+
{
108+
nextAddr = it.first + it.second;
109+
auto it2 = freeMap.find(nextAddr);
110+
if (nextAddr % 262144 != 0 && it2 != freeMap.end())
111+
{
112+
found = true;
113+
thisAddr = it.first;
114+
newLen = it.second + it2->second;
115+
break;
116+
}
117+
}
118+
if (!found)
119+
{
120+
break;
121+
}
122+
freeMap[thisAddr] = newLen;
123+
freeMap.erase(nextAddr);
124+
}
125+
#if GUS_ALLOC_DEBUG_LOG
126+
printf("defrag[");
127+
bool first = true;
128+
for (auto it : freeMap)
129+
{
130+
if (!first)
131+
{
132+
printf("|");
133+
}
134+
printf("%x %x", it.first, it.first + it.second);
135+
first = false;
136+
}
137+
printf("]\n");
138+
#endif
86139
}
87140

88141
void MinialGUS::gusSetVolume(uint8_t voice, ALfloat listenerGain, ALfloat sourceGain)
@@ -135,12 +188,29 @@ void MinialGUS::DeleteSources(ALsizei n, const ALuint* sources)
135188
if (sources[i] > 0 && sources[i] <= (ALuint)m_gusVoices)
136189
{
137190
sourceMap[sources[i] - 1].alloc = false;
191+
if (sourceMap[sources[i] - 1].buffer)
192+
{
193+
auto it = bufferMap.find(sourceMap[sources[i] - 1].buffer);
194+
if (it != bufferMap.end())
195+
{
196+
MA_GUS_Buffer& buf = it->second;
197+
--buf.refcount;
198+
}
199+
}
138200
}
139201
}
140202
}
141203
void MinialGUS::DeleteBuffers(ALsizei n, const ALuint* buffers)
142204
{
143-
for (int i = 0; i != n; ++i)
205+
for (ALsizei i = 0; i != n; ++i)
206+
{
207+
if (bufferMap[buffers[i]].refcount != 0)
208+
{
209+
m_error = AL_INVALID_OPERATION;
210+
return;
211+
}
212+
}
213+
for (ALsizei i = 0; i != n; ++i)
144214
{
145215
gusFree(bufferMap[buffers[i]].addr);
146216
}
@@ -162,7 +232,22 @@ void MinialGUS::BufferData(ALuint buffer, ALenum format, const ALvoid* data, ALs
162232
MA_GUS_Buffer& buff = bufferMap[buffer];
163233
buff.pitch = float(freq) / float(m_freq);
164234

235+
gusFree(buff.addr);
165236
buff.addr = gusAlloc(size);
237+
#if GUS_ALLOC_DEBUG_LOG
238+
printf("alloc[");
239+
bool first = true;
240+
for (auto it : freeMap)
241+
{
242+
if (!first)
243+
{
244+
printf("|");
245+
}
246+
printf("%x %x", it.first, it.first + it.second);
247+
first = false;
248+
}
249+
printf("]\n");
250+
#endif
166251
if (buff.addr != GUS_INVALID_ALLOC)
167252
{
168253
buff.len = size;
@@ -171,6 +256,10 @@ void MinialGUS::BufferData(ALuint buffer, ALenum format, const ALvoid* data, ALs
171256
GUSPoke(buff.addr + i, ((int16_t*)data)[i] / 256);
172257
}
173258
}
259+
else
260+
{
261+
m_error = AL_OUT_OF_MEMORY;
262+
}
174263
}
175264
void MinialGUS::Sourcef(ALuint source, ALenum param, ALfloat value)
176265
{
@@ -260,6 +349,26 @@ void MinialGUS::Sourcei(ALuint source, ALenum param, ALint value)
260349
}
261350
else
262351
{
352+
if (src.buffer)
353+
{
354+
auto it = bufferMap.find(src.buffer);
355+
if (it != bufferMap.end())
356+
{
357+
MA_GUS_Buffer& buf = it->second;
358+
--buf.refcount;
359+
}
360+
}
361+
if (value)
362+
{
363+
auto it = bufferMap.find(value);
364+
if (it == bufferMap.end())
365+
{
366+
m_error = AL_INVALID_NAME;
367+
return;
368+
}
369+
MA_GUS_Buffer& buf = it->second;
370+
++buf.refcount;
371+
}
263372
src.buffer = value;
264373
}
265374
break;

src/minial_gus.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct MA_GUS_Buffer
2525
ALfloat pitch{1.0};
2626
uint32_t addr{GUS_INVALID_ALLOC};
2727
uint32_t len{0};
28-
uint32_t refs{0}; // TODO count referring sources
28+
uint32_t refcount{0}; // TODO count referring sources
2929
};
3030

3131
class MinialGUS : public MinialInterface
@@ -56,9 +56,11 @@ class MinialGUS : public MinialInterface
5656

5757
private:
5858
std::map<uint32_t, uint32_t> freeMap;
59+
std::map<uint32_t, uint32_t> allocMap;
5960

6061
uint32_t gusAlloc(uint32_t len);
6162
void gusFree(uint32_t pos);
63+
void gusDefrag(void);
6264
void gusSetVolume(uint8_t voice, ALfloat listenerGain, ALfloat sourceGain);
6365

6466
ALfloat m_listenerGain = 1.f;

src/minial_sb.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,32 @@ void MinialSB::GenBuffers(ALsizei n, ALuint* buffers)
160160

161161
void MinialSB::DeleteSources(ALsizei n, const ALuint* sources)
162162
{
163+
for (ALsizei i = 0; i != n; ++i)
164+
{
165+
ALuint buf = sourceMap[sources[i]].buffer;
166+
if (buf)
167+
{
168+
auto it = bufferMap.find(buf);
169+
if (it != bufferMap.end())
170+
{
171+
MA_SB_Buffer& buf = it->second;
172+
--buf.refcount;
173+
}
174+
}
175+
}
163176
deleteStuff(n, sources, sourceMap);
164177
}
165178

166179
void MinialSB::DeleteBuffers(ALsizei n, const ALuint* buffers)
167180
{
181+
for (ALsizei i = 0; i != n; ++i)
182+
{
183+
if (bufferMap[buffers[i]].refcount != 0)
184+
{
185+
m_error = AL_INVALID_OPERATION;
186+
return;
187+
}
188+
}
168189
deleteStuff(n, buffers, bufferMap);
169190
}
170191

@@ -257,6 +278,26 @@ void MinialSB::Sourcei(ALuint source, ALenum param, ALint value)
257278
}
258279
else
259280
{
281+
if (src.buffer)
282+
{
283+
auto it = bufferMap.find(src.buffer);
284+
if (it != bufferMap.end())
285+
{
286+
MA_SB_Buffer& buf = it->second;
287+
--buf.refcount;
288+
}
289+
}
290+
if (value)
291+
{
292+
auto it = bufferMap.find(value);
293+
if (it == bufferMap.end())
294+
{
295+
m_error = AL_INVALID_NAME;
296+
return;
297+
}
298+
MA_SB_Buffer& buf = it->second;
299+
++buf.refcount;
300+
}
260301
src.buffer = value;
261302
}
262303
break;

src/minial_sb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ struct MA_SB_Buffer
3434
{
3535
std::vector<Uint16> samples;
3636
float pitch = 1.f;
37+
uint32_t refcount{0}; // TODO count referring sources
3738
};
3839

3940
class MinialSB : public MinialInterface

src/soundmng.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,31 @@ void Sound_game_static::init()
4949
alGenBuffers(1, &(p_hit_sample[0])); global_al_buffers.push_back(p_hit_sample[0]);
5050
swapArrayLE16(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
5151
alBufferData(p_hit_sample[0], AL_FORMAT_MONO16, gbuff_in.fbuffptr(), gbuff_in.fbuffsz(), smallSampleRam() ? 11025 : 22050);
52+
if (alGetError() == AL_OUT_OF_MEMORY)
53+
{
54+
fprintf(stderr, "AL buffer data allocation error\n");
55+
}
5256
gbuff_in.fclose();
5357

5458
gbuff_in.f_open("crash1.raw", "rb");if (smallSampleRam())gbuff_in.downsampleAudio16();
5559
alGenBuffers(1, &(p_hit_sample[1])); global_al_buffers.push_back(p_hit_sample[1]);
5660
swapArrayLE16(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
5761
alBufferData(p_hit_sample[1], AL_FORMAT_MONO16, gbuff_in.fbuffptr(), gbuff_in.fbuffsz(), smallSampleRam() ? 11025 : 22050);
62+
if (alGetError() == AL_OUT_OF_MEMORY)
63+
{
64+
fprintf(stderr, "AL buffer data allocation error\n");
65+
}
5866
gbuff_in.fclose();
5967

6068
gbuff_in.f_open("skid.raw", "rb");if (smallSampleRam())gbuff_in.downsampleAudio16();
6169
alGenBuffers(1, &(p_skid_sample)); global_al_buffers.push_back(p_skid_sample);
6270
swapArrayLE16(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
6371
tweakLoop(gbuff_in.fbuffptr(), gbuff_in.fbuffsz());
6472
alBufferData(p_skid_sample, AL_FORMAT_MONO16, gbuff_in.fbuffptr(), gbuff_in.fbuffsz(), smallSampleRam() ? 11025 : 22050);
73+
if (alGetError() == AL_OUT_OF_MEMORY)
74+
{
75+
fprintf(stderr, "AL buffer data allocation error\n");
76+
}
6577
gbuff_in.fclose();
6678

6779
for (unsigned int i = 0; i != 4; ++i) {

src/utest_al/main.cpp

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,31 +37,42 @@ int main(int argc, char** argv)
3737
alListenerfv(AL_ORIENTATION, listenerOri);
3838
alListenerf(AL_GAIN, 1.0);
3939

40-
std::vector<uint8_t> wavData;
41-
if (loadWav("monti.wav", wavData))
40+
// unit test suite start
41+
int errCount = 0;
42+
if (true)
4243
{
43-
printf("error loading wav data\n");
44-
}
44+
ALuint sampleA, sampleB;
45+
std::vector<uint8_t> wavData;
46+
if (loadWav("monti.wav", wavData))
47+
{
48+
printf("error loading wav data\n");
49+
}
4550

46-
ALuint buffers[2];
47-
alGenBuffers(2, buffers);
48-
sampleA = buffers[0];
49-
sampleB = buffers[1];
50-
alBufferData(sampleA, AL_FORMAT_MONO16, wavData.data(), wavData.size(), 22050);
51+
ALuint buffers[2];
52+
alGenBuffers(2, buffers);
53+
utAlErrCheck(__LINE__);
5154

52-
if (loadWav("handel.wav", wavData))
53-
{
54-
printf("error loading wav data\n");
55-
}
55+
sampleA = buffers[0];
56+
sampleB = buffers[1];
57+
alBufferData(sampleA, AL_FORMAT_MONO16, wavData.data(), wavData.size(), 22050);
58+
utAlErrCheck(__LINE__);
5659

57-
alBufferData(sampleB, AL_FORMAT_MONO16, wavData.data(), wavData.size(), 22050);
60+
if (loadWav("handel.wav", wavData))
61+
{
62+
printf("error loading wav data\n");
63+
}
5864

59-
// unit test suite start
65+
alBufferData(sampleB, AL_FORMAT_MONO16, wavData.data(), wavData.size(), 22050);
66+
utAlErrCheck(__LINE__);
6067

61-
int errCount = 0;
68+
errCount += testBufferSwitch(sampleA, sampleB);
69+
errCount += testGain(sampleA);
70+
71+
alDeleteBuffers(2, buffers);
72+
utAlErrCheck(__LINE__);
73+
}
6274

63-
errCount += testBufferSwitch();
64-
errCount += testGain();
75+
errCount += testBufferRefs();
6576

6677
// unit test suite end
6778

0 commit comments

Comments
 (0)