]> git.sesse.net Git - vlc/blob - modules/audio_output/TPCircularBuffer.c
direct3d11: catch texture mapping errors
[vlc] / modules / audio_output / TPCircularBuffer.c
1 //
2 //  TPCircularBuffer.c
3 //  Circular/Ring buffer implementation
4 //
5 //  Created by Michael Tyson on 10/12/2011.
6 //  Copyright 2011-2012 A Tasty Pixel. All rights reserved.
7
8
9 #include "audio_output/TPCircularBuffer.h"
10 #include <mach/mach.h>
11 #include <stdio.h>
12
13 #define reportResult(result,operation) (_reportResult((result),(operation),strrchr(__FILE__, '/')+1,__LINE__))
14 static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) {
15     if ( result != ERR_SUCCESS ) {
16         printf("%s:%d: %s: %s\n", file, line, operation, mach_error_string(result));
17         return false;
18     }
19     return true;
20 }
21
22 bool TPCircularBufferInit(TPCircularBuffer *buffer, int length) {
23
24     // Keep trying until we get our buffer, needed to handle race conditions
25     int retries = 3;
26     while ( true ) {
27
28         buffer->length = round_page(length);    // We need whole page sizes
29
30         // Temporarily allocate twice the length, so we have the contiguous address space to
31         // support a second instance of the buffer directly after
32         vm_address_t bufferAddress;
33         kern_return_t result = vm_allocate(mach_task_self(),
34                                            &bufferAddress,
35                                            buffer->length * 2,
36                                            VM_FLAGS_ANYWHERE); // allocate anywhere it'll fit
37         if ( result != ERR_SUCCESS ) {
38             if ( retries-- == 0 ) {
39                 reportResult(result, "Buffer allocation");
40                 return false;
41             }
42             // Try again if we fail
43             continue;
44         }
45
46         // Now replace the second half of the allocation with a virtual copy of the first half. Deallocate the second half...
47         result = vm_deallocate(mach_task_self(),
48                                bufferAddress + buffer->length,
49                                buffer->length);
50         if ( result != ERR_SUCCESS ) {
51             if ( retries-- == 0 ) {
52                 reportResult(result, "Buffer deallocation");
53                 return false;
54             }
55             // If this fails somehow, deallocate the whole region and try again
56             vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
57             continue;
58         }
59
60         // Re-map the buffer to the address space immediately after the buffer
61         vm_address_t virtualAddress = bufferAddress + buffer->length;
62         vm_prot_t cur_prot, max_prot;
63         result = vm_remap(mach_task_self(),
64                           &virtualAddress,   // mirror target
65                           buffer->length,    // size of mirror
66                           0,                 // auto alignment
67                           0,                 // force remapping to virtualAddress
68                           mach_task_self(),  // same task
69                           bufferAddress,     // mirror source
70                           0,                 // MAP READ-WRITE, NOT COPY
71                           &cur_prot,         // unused protection struct
72                           &max_prot,         // unused protection struct
73                           VM_INHERIT_DEFAULT);
74         if ( result != ERR_SUCCESS ) {
75             if ( retries-- == 0 ) {
76                 reportResult(result, "Remap buffer memory");
77                 return false;
78             }
79             // If this remap failed, we hit a race condition, so deallocate and try again
80             vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
81             continue;
82         }
83
84         if ( virtualAddress != bufferAddress+buffer->length ) {
85             // If the memory is not contiguous, clean up both allocated buffers and try again
86             if ( retries-- == 0 ) {
87                 printf("Couldn't map buffer memory to end of buffer\n");
88                 return false;
89             }
90
91             vm_deallocate(mach_task_self(), virtualAddress, buffer->length);
92             vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
93             continue;
94         }
95
96         buffer->buffer = (void*)bufferAddress;
97         buffer->fillCount = 0;
98         buffer->head = buffer->tail = 0;
99
100         return true;
101     }
102     return false;
103 }
104
105 void TPCircularBufferCleanup(TPCircularBuffer *buffer) {
106     vm_deallocate(mach_task_self(), (vm_address_t)buffer->buffer, buffer->length * 2);
107     memset(buffer, 0, sizeof(TPCircularBuffer));
108 }
109
110 void TPCircularBufferClear(TPCircularBuffer *buffer) {
111     int32_t fillCount;
112     if ( TPCircularBufferTail(buffer, &fillCount) ) {
113         TPCircularBufferConsume(buffer, fillCount);
114     }
115 }