~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to GPU/Debugger/Breakpoints.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <vector>
 
19
#include <set>
 
20
#include "base/mutex.h"
 
21
#include "GPU/Debugger/Breakpoints.h"
 
22
#include "GPU/GPUState.h"
 
23
 
 
24
namespace GPUBreakpoints {
 
25
 
 
26
static recursive_mutex breaksLock;
 
27
static std::vector<bool> breakCmds;
 
28
static std::set<u32> breakPCs;
 
29
static std::set<u32> breakTextures;
 
30
static std::set<u32> breakRenderTargets;
 
31
// Small optimization to avoid a lock/lookup for the common case.
 
32
static size_t breakPCsCount = 0;
 
33
static size_t breakTexturesCount = 0;
 
34
static size_t breakRenderTargetsCount = 0;
 
35
 
 
36
// If these are set, the above are also, but they should be temporary.
 
37
static std::vector<bool> breakCmdsTemp;
 
38
static std::set<u32> breakPCsTemp;
 
39
static std::set<u32> breakTexturesTemp;
 
40
static std::set<u32> breakRenderTargetsTemp;
 
41
static bool textureChangeTemp = false;
 
42
 
 
43
static u32 lastTexture = 0xFFFFFFFF;
 
44
 
 
45
// These are commands we run before breaking on a texture.
 
46
// They are commands that affect the decoding of the texture.
 
47
const static u8 textureRelatedCmds[] = {
 
48
        GE_CMD_TEXADDR0, GE_CMD_TEXADDR1, GE_CMD_TEXADDR2, GE_CMD_TEXADDR3, GE_CMD_TEXADDR4, GE_CMD_TEXADDR5, GE_CMD_TEXADDR6, GE_CMD_TEXADDR7,
 
49
        GE_CMD_TEXBUFWIDTH0, GE_CMD_TEXBUFWIDTH1, GE_CMD_TEXBUFWIDTH2, GE_CMD_TEXBUFWIDTH3, GE_CMD_TEXBUFWIDTH4, GE_CMD_TEXBUFWIDTH5, GE_CMD_TEXBUFWIDTH6, GE_CMD_TEXBUFWIDTH7,
 
50
        GE_CMD_TEXSIZE0, GE_CMD_TEXSIZE1, GE_CMD_TEXSIZE2, GE_CMD_TEXSIZE3, GE_CMD_TEXSIZE4, GE_CMD_TEXSIZE5, GE_CMD_TEXSIZE6, GE_CMD_TEXSIZE7,
 
51
 
 
52
        GE_CMD_CLUTADDR, GE_CMD_CLUTADDRUPPER, GE_CMD_LOADCLUT, GE_CMD_CLUTFORMAT,
 
53
        GE_CMD_TEXFORMAT, GE_CMD_TEXMODE, GE_CMD_TEXTUREMAPENABLE,
 
54
        GE_CMD_TEXFILTER, GE_CMD_TEXWRAP,
 
55
        GE_CMD_TEXLEVEL,
 
56
 
 
57
        // Sometimes found between clut/texture params.
 
58
        GE_CMD_TEXFLUSH, GE_CMD_TEXSYNC,
 
59
};
 
60
static std::vector<bool> nonTextureCmds;
 
61
 
 
62
void Init() {
 
63
        ClearAllBreakpoints();
 
64
 
 
65
        nonTextureCmds.clear();
 
66
        nonTextureCmds.resize(256, true);
 
67
        for (size_t i = 0; i < ARRAY_SIZE(textureRelatedCmds); ++i) {
 
68
                nonTextureCmds[textureRelatedCmds[i]] = false;
 
69
        }
 
70
}
 
71
 
 
72
void AddNonTextureTempBreakpoints() {
 
73
        for (int i = 0; i < 256; ++i) {
 
74
                if (nonTextureCmds[i]) {
 
75
                        AddCmdBreakpoint(i, true);
 
76
                }
 
77
        }
 
78
}
 
79
 
 
80
u32 GetAdjustedTextureAddress(u32 op) {
 
81
        const u8 cmd = op >> 24;
 
82
        bool interesting = (cmd >= GE_CMD_TEXADDR0 && cmd <= GE_CMD_TEXADDR7);
 
83
        interesting = interesting || (cmd >= GE_CMD_TEXBUFWIDTH0 && cmd <= GE_CMD_TEXBUFWIDTH7);
 
84
 
 
85
        if (!interesting) {
 
86
                return (u32)-1;
 
87
        }
 
88
 
 
89
        int level = cmd <= GE_CMD_TEXADDR7 ? cmd - GE_CMD_TEXADDR0 : cmd - GE_CMD_TEXBUFWIDTH0;
 
90
        u32 addr;
 
91
 
 
92
        // Okay, so would this op modify the low or high part?
 
93
        if (cmd <= GE_CMD_TEXADDR7) {
 
94
                addr = (op & 0xFFFFF0) | ((gstate.texbufwidth[level] << 8) & 0x0F000000);
 
95
        } else {
 
96
                addr = (gstate.texaddr[level] & 0xFFFFF0) | ((op << 8) & 0x0F000000);
 
97
        }
 
98
 
 
99
        return addr;
 
100
}
 
101
 
 
102
u32 GetAdjustedRenderTargetAddress(u32 op) {
 
103
        const u8 cmd = op >> 24;
 
104
        switch (cmd) {
 
105
        case GE_CMD_FRAMEBUFPTR:
 
106
        case GE_CMD_ZBUFPTR:
 
107
                return op & 0x003FFFF0;
 
108
        }
 
109
 
 
110
        return (u32)-1;
 
111
}
 
112
 
 
113
bool IsTextureChangeBreakpoint(u32 op, u32 addr) {
 
114
        if (!textureChangeTemp) {
 
115
                return false;
 
116
        }
 
117
 
 
118
        const u8 cmd = op >> 24;
 
119
        bool enabled = gstate.isTextureMapEnabled();
 
120
 
 
121
        // Only for level 0.
 
122
        if (cmd != GE_CMD_TEXADDR0 && cmd != GE_CMD_TEXBUFWIDTH0) {
 
123
                // But we don't break when it's not enabled.
 
124
                if (cmd == GE_CMD_TEXTUREMAPENABLE) {
 
125
                        enabled = (op & 1) != 0;
 
126
                } else {
 
127
                        return false;
 
128
                }
 
129
        }
 
130
        if (enabled && addr != lastTexture) {
 
131
                textureChangeTemp = false;
 
132
                lastTexture = addr;
 
133
                return true;
 
134
        } else {
 
135
                return false;
 
136
        }
 
137
}
 
138
 
 
139
bool IsTextureCmdBreakpoint(u32 op) {
 
140
        const u32 addr = GetAdjustedTextureAddress(op);
 
141
        if (addr != (u32)-1) {
 
142
                return IsTextureChangeBreakpoint(op, addr) || IsTextureBreakpoint(addr);
 
143
        } else {
 
144
                return IsTextureChangeBreakpoint(op, gstate.getTextureAddress(0));
 
145
        }
 
146
}
 
147
 
 
148
bool IsRenderTargetCmdBreakpoint(u32 op) {
 
149
        const u32 addr = GetAdjustedRenderTargetAddress(op);
 
150
        if (addr != (u32)-1) {
 
151
                return IsRenderTargetBreakpoint(addr);
 
152
        }
 
153
        return false;
 
154
}
 
155
 
 
156
bool IsBreakpoint(u32 pc, u32 op) {
 
157
        if (IsAddressBreakpoint(pc) || IsOpBreakpoint(op)) {
 
158
                return true;
 
159
        }
 
160
 
 
161
        if ((breakTexturesCount != 0 || textureChangeTemp) && IsTextureCmdBreakpoint(op)) {
 
162
                // Break on the next non-texture.
 
163
                AddNonTextureTempBreakpoints();
 
164
        }
 
165
        if (breakRenderTargetsCount != 0 && IsRenderTargetCmdBreakpoint(op)) {
 
166
                return true;
 
167
        }
 
168
 
 
169
        return false;
 
170
}
 
171
 
 
172
bool IsAddressBreakpoint(u32 addr, bool &temp) {
 
173
        if (breakPCsCount == 0) {
 
174
                temp = false;
 
175
                return false;
 
176
        }
 
177
 
 
178
        lock_guard guard(breaksLock);
 
179
        temp = breakPCsTemp.find(addr) != breakPCsTemp.end();
 
180
        return breakPCs.find(addr) != breakPCs.end();
 
181
}
 
182
 
 
183
bool IsAddressBreakpoint(u32 addr) {
 
184
        if (breakPCsCount == 0) {
 
185
                return false;
 
186
        }
 
187
 
 
188
        lock_guard guard(breaksLock);
 
189
        return breakPCs.find(addr) != breakPCs.end();
 
190
}
 
191
 
 
192
bool IsTextureBreakpoint(u32 addr, bool &temp) {
 
193
        if (breakTexturesCount == 0) {
 
194
                temp = false;
 
195
                return false;
 
196
        }
 
197
 
 
198
        lock_guard guard(breaksLock);
 
199
        temp = breakTexturesTemp.find(addr) != breakTexturesTemp.end();
 
200
        return breakTextures.find(addr) != breakTextures.end();
 
201
}
 
202
 
 
203
bool IsTextureBreakpoint(u32 addr) {
 
204
        if (breakTexturesCount == 0) {
 
205
                return false;
 
206
        }
 
207
 
 
208
        lock_guard guard(breaksLock);
 
209
        return breakTextures.find(addr) != breakTextures.end();
 
210
}
 
211
 
 
212
bool IsRenderTargetBreakpoint(u32 addr, bool &temp) {
 
213
        if (breakRenderTargetsCount == 0) {
 
214
                temp = false;
 
215
                return false;
 
216
        }
 
217
 
 
218
        addr &= 0x003FFFF0;
 
219
 
 
220
        lock_guard guard(breaksLock);
 
221
        temp = breakRenderTargetsTemp.find(addr) != breakRenderTargetsTemp.end();
 
222
        return breakRenderTargets.find(addr) != breakRenderTargets.end();
 
223
}
 
224
 
 
225
bool IsRenderTargetBreakpoint(u32 addr) {
 
226
        if (breakRenderTargetsCount == 0) {
 
227
                return false;
 
228
        }
 
229
 
 
230
        addr &= 0x003FFFF0;
 
231
 
 
232
        lock_guard guard(breaksLock);
 
233
        return breakRenderTargets.find(addr) != breakRenderTargets.end();
 
234
}
 
235
 
 
236
bool IsOpBreakpoint(u32 op, bool &temp) {
 
237
        return IsCmdBreakpoint(op >> 24, temp);
 
238
}
 
239
 
 
240
bool IsOpBreakpoint(u32 op) {
 
241
        return IsCmdBreakpoint(op >> 24);
 
242
}
 
243
 
 
244
bool IsCmdBreakpoint(u8 cmd, bool &temp) {
 
245
        temp = breakCmdsTemp[cmd];
 
246
        return breakCmds[cmd];
 
247
}
 
248
 
 
249
bool IsCmdBreakpoint(u8 cmd) {
 
250
        return breakCmds[cmd];
 
251
}
 
252
 
 
253
void AddAddressBreakpoint(u32 addr, bool temp) {
 
254
        lock_guard guard(breaksLock);
 
255
 
 
256
        if (temp) {
 
257
                if (breakPCs.find(addr) == breakPCs.end()) {
 
258
                        breakPCsTemp.insert(addr);
 
259
                        breakPCs.insert(addr);
 
260
                }
 
261
                // Already normal breakpoint, let's not make it temporary.
 
262
        } else {
 
263
                // Remove the temporary marking.
 
264
                breakPCsTemp.erase(addr);
 
265
                breakPCs.insert(addr);
 
266
        }
 
267
 
 
268
        breakPCsCount = breakPCs.size();
 
269
}
 
270
 
 
271
void AddCmdBreakpoint(u8 cmd, bool temp) {
 
272
        if (temp) {
 
273
                if (!breakCmds[cmd]) {
 
274
                        breakCmdsTemp[cmd] = true;
 
275
                        breakCmds[cmd] = true;
 
276
                }
 
277
                // Ignore adding a temp breakpoint when a normal one exists.
 
278
        } else {
 
279
                // This is no longer temporary.
 
280
                breakCmdsTemp[cmd] = false;
 
281
                breakCmds[cmd] = true;
 
282
        }
 
283
}
 
284
 
 
285
void AddTextureBreakpoint(u32 addr, bool temp) {
 
286
        lock_guard guard(breaksLock);
 
287
 
 
288
        if (temp) {
 
289
                if (breakTextures.find(addr) == breakTextures.end()) {
 
290
                        breakTexturesTemp.insert(addr);
 
291
                        breakTextures.insert(addr);
 
292
                }
 
293
        } else {
 
294
                breakTexturesTemp.erase(addr);
 
295
                breakTextures.insert(addr);
 
296
        }
 
297
 
 
298
        breakTexturesCount = breakTextures.size();
 
299
}
 
300
 
 
301
void AddRenderTargetBreakpoint(u32 addr, bool temp) {
 
302
        lock_guard guard(breaksLock);
 
303
 
 
304
        addr &= 0x003FFFF0;
 
305
 
 
306
        if (temp) {
 
307
                if (breakRenderTargets.find(addr) == breakRenderTargets.end()) {
 
308
                        breakRenderTargetsTemp.insert(addr);
 
309
                        breakRenderTargets.insert(addr);
 
310
                }
 
311
        } else {
 
312
                breakRenderTargetsTemp.erase(addr);
 
313
                breakRenderTargets.insert(addr);
 
314
        }
 
315
 
 
316
        breakRenderTargetsCount = breakRenderTargets.size();
 
317
}
 
318
 
 
319
void AddTextureChangeTempBreakpoint() {
 
320
        textureChangeTemp = true;
 
321
}
 
322
 
 
323
void RemoveAddressBreakpoint(u32 addr) {
 
324
        lock_guard guard(breaksLock);
 
325
 
 
326
        breakPCsTemp.erase(addr);
 
327
        breakPCs.erase(addr);
 
328
 
 
329
        breakPCsCount = breakPCs.size();
 
330
}
 
331
 
 
332
void RemoveCmdBreakpoint(u8 cmd) {
 
333
        breakCmdsTemp[cmd] = false;
 
334
        breakCmds[cmd] = false;
 
335
}
 
336
 
 
337
void RemoveTextureBreakpoint(u32 addr) {
 
338
        lock_guard guard(breaksLock);
 
339
 
 
340
        breakTexturesTemp.erase(addr);
 
341
        breakTextures.erase(addr);
 
342
 
 
343
        breakTexturesCount = breakTextures.size();
 
344
}
 
345
 
 
346
void RemoveRenderTargetBreakpoint(u32 addr) {
 
347
        lock_guard guard(breaksLock);
 
348
 
 
349
        addr &= 0x003FFFF0;
 
350
 
 
351
        breakRenderTargetsTemp.erase(addr);
 
352
        breakRenderTargets.erase(addr);
 
353
 
 
354
        breakRenderTargetsCount = breakRenderTargets.size();
 
355
}
 
356
 
 
357
void RemoveTextureChangeTempBreakpoint() {
 
358
        textureChangeTemp = false;
 
359
}
 
360
 
 
361
void UpdateLastTexture(u32 addr) {
 
362
        lastTexture = addr;
 
363
}
 
364
 
 
365
void ClearAllBreakpoints() {
 
366
        lock_guard guard(breaksLock);
 
367
 
 
368
        breakCmds.clear();
 
369
        breakCmds.resize(256, false);
 
370
        breakPCs.clear();
 
371
        breakTextures.clear();
 
372
        breakRenderTargets.clear();
 
373
 
 
374
        breakCmdsTemp.clear();
 
375
        breakCmdsTemp.resize(256, false);
 
376
        breakPCsTemp.clear();
 
377
        breakTexturesTemp.clear();
 
378
        breakRenderTargetsTemp.clear();
 
379
 
 
380
        breakPCsCount = breakPCs.size();
 
381
        breakTexturesCount = breakTextures.size();
 
382
        breakRenderTargetsCount = breakRenderTargets.size();
 
383
 
 
384
        textureChangeTemp = false;
 
385
}
 
386
 
 
387
void ClearTempBreakpoints() {
 
388
        lock_guard guard(breaksLock);
 
389
 
 
390
        // Reset ones that were temporary back to non-breakpoints in the primary arrays.
 
391
        for (int i = 0; i < 256; ++i) {
 
392
                if (breakCmdsTemp[i]) {
 
393
                        breakCmds[i] = false;
 
394
                        breakCmdsTemp[i] = false;
 
395
                }
 
396
        }
 
397
 
 
398
        for (auto it = breakPCsTemp.begin(), end = breakPCsTemp.end(); it != end; ++it) {
 
399
                breakPCs.erase(*it);
 
400
        }
 
401
        breakPCsTemp.clear();
 
402
        breakPCsCount = breakPCs.size();
 
403
 
 
404
        for (auto it = breakTexturesTemp.begin(), end = breakTexturesTemp.end(); it != end; ++it) {
 
405
                breakTextures.erase(*it);
 
406
        }
 
407
        breakTexturesTemp.clear();
 
408
        breakTexturesCount = breakTextures.size();
 
409
 
 
410
        for (auto it = breakRenderTargetsTemp.begin(), end = breakRenderTargetsTemp.end(); it != end; ++it) {
 
411
                breakRenderTargets.erase(*it);
 
412
        }
 
413
        breakRenderTargetsTemp.clear();
 
414
        breakRenderTargetsCount = breakRenderTargets.size();
 
415
 
 
416
        textureChangeTemp = false;
 
417
}
 
418
 
 
419
};